46. while-Schleifen

while

-Schleifen sollten zum Einsatz kommen, wenn etwas ausgeführt werden soll, solange eine Bedingung erfüllt ist, man also nicht von vorneherein weiß, wie lange iteriert werden soll.

Ein etwas albernes Beispiel: Nehmen wir an, am Rechner hängt ein Temperaturfühler, den wir mit einer Funktion getTemperature() auslesen können (das ist nicht so, es sei denn, ihr schreibt euch sowas selbst). Wenn wir jetzt ein Programm schreiben wollten, das jedes Mal, wenn die Temperatur einen kritischen Wert überschreitet, eine Warnung ausgibt, dann aber leise sein soll, bis die Temperatur wieder normal ist und erst danach wieder auf Überschreitung kontrollieren soll, könnten wir das so machen:

critVal = 40.0
while 1:
  while getTemperature()<critVal:
    time.sleep(1)
  warnUser()
  while getTemperature()>critVal:
    time.sleep(1)

Die Funktion sleep aus dem time-Modul sorgt dafür, dass der Rechner für eine Weile (nämlich so viele Sekunden wie im Argument angegeben) nichts tut. Die Technik, in einer Schleife regelmäßig nach etwas zu sehen, heißt übrigens polling und sollte in der Regel vermieden werden – über Alternativen werden wir in Programmieren II reden.

Das Konstrukt while 1: erzeugt eine Endlosschleife. In diesem Fall wollen wir ja wirklich endlos überwachen.

Häufig sind auch Konstrukte wie

while 1:
  doSomeStuff()
  if someCondition():
    break
  doMoreStuff()

– sie sind immer dann Mittel der Wahl, wenn das Abbruchkriterium logisch am Besten mitten im Schleifenkörper selbst berechnet werden kann. Man sollte darauf achten, dass nicht zu viele breaks und continues in einem Schleifenkörper stehen (generell sollten Schleifenkörper ohnehin nicht mehr als vielleicht 10 Zeilen haben), weil sonst der control flow sehr undurchsichtig wird. In Maßen verwendet, kann sowas die Lesbarkeit eines Programms aber – entgegen den Aussagen gewisser Stilpäpste – durchaus erhöhen.

Ein weiteres Beispiel zu while ist die Mandelbrotmenge. Die Details sind nicht so wichtig, die Vorschrift ist jedenfalls, die Gleichung zn+1 = zn2 + c (in Python wäre das also z=z**2+c) so lange zu iterieren, bis eine vorher vereinbarte Anzahl von Iterationen gemacht wurde oder eine vorher vereinbare Zahl von Iterationen gemacht wurde. Die Funktion, die das tut, soll dann zurückgeben, wie viele Iterationen sie gebraucht hat.

Code zur Berechnung könne so aussehen:

def iterate(point, maxIter=200):
  numIter = 0
  z = 0j
  while abs(z)<2 and numIter<maxIter:
    z = z*z+point
    numIter += 1
  return numIter

(das 0j sagt, dass es sich bei z um eine komplexe Zahl handelt – ich sagte ja, dass die Details hier nicht so wichtig sind).

Eingebunden in ein Programm wie

def scalediter(minVal, maxVal, numPoints):
  scaleFact = (maxVal-minVal)/float(numPoints)
  for val in xrange(numPoints+1):
    yield val, val*scaleFact+minVal

class MandelDrawer:
  def __init__(self, displayer):
    self.displayer = displayer

  def drawImg(self, minX=-1.75, minY=-1, maxX=0.5, maxY=1):
    numPixels = self.displayer.getNumPixels()
    for y, ys in scalediter(minY, maxY, numPixels):
      for x, xs in scalediter(minX, maxX, numPixels):
        val = iterate(complex(xs, ys), 512)
        self.displayer.setPoint(x, y,
          "#%02x00%02x"%(val%256, (256-val/2)%256))
      self.displayer.updateDisplay()

if __name__=="__main__":
  _test()
  p = pixelCanvas.PixelCanvas(2, 100)
  m = MandelDrawer(p)
  m.drawImg()
  p.mainloop()

kann man damit schon die vor einigen Jahren furchbar populären Apfelmännchen malen, wenn auch eher langsam:

Dabei gibts das pixelCanvas-Modul im Anhang (was darin geschieht, ist erst nach unserem Ausflug in die GUIs verständlich). In der komischen scaledIter-Funktion haben wir der Bequemlichkeit halber schon auf Generatoren zurückgegriffen, die wir erst auf der Folie “Generatoren und Iteratoren” diskutieren werden.

Natürlich würde niemand, der/die seine/ihre Sinne noch beieinander hat, diese Sorte von Heavy-Duty-Numerik ernsthaft direkt in Python machen. Wir werden zwar in Programmieren II Techniken kennenlernen, wie wir allzu viel C (oder Fortran oder was immer) in solchen Aufgaben vermeiden können – wer aber jetzt schon schnell schöne Bilder sehen will, sei auf XaoS verwiesen.

Übungen zu diesem Abschnitt

Ihr solltet euch wenigstens an den rötlich unterlegten Aufgaben versuchen

(1)

While- und for-Schleifen sind im Wesentlichen äquivalent, d.h. man kann alle for-Schleifen auch durch while-Scheifen ersetzen und umgekehrt (auch wenn letzteres in Python ein wenig Getrickse braucht).

Wie sieht die folgende Schleife in while-Form aus?

for i in range(10):
  print i

Dateien zu diesem Abschnitt


Markus Demleitner

Copyright Notice