Die Programmiersprache Python


Index

  1. Charakterisierung und Historie
  2. Einsatzgebiete
  3. Eigenschaften und Merkmale von Python
  4. Die wichtigsten Daten-/Objekt-Typen
  5. Variablen
  6. Kleine Auswahl von Konzepten und Besonderheiten
  7. In medias res - praktischer Einstieg an Beispielen
  8. Namensräume und Sichtbarkeitsbereiche
  9. Funktionen
  10. Objekt-Orientierung
  11. Sammlung von Code-Beispielen
  12. Links und Literatur zu Python

1. Charakterisierung und Historie


2. Einsatzgebiete


3. Eigenschaften und Merkmale von Python


4. Die wichtigsten Daten-/Objekt-Typen


5. Variablen


6. Kleine Auswahl von Konzepten und Besonderheiten


7. In medias res - praktischer Einstieg an Beispielen

Index:

  1. Hello World
  2. Programmierparadigmen
  3. Zugriff auf Argumenteliste und Umgebung
  4. Rechnen mit Python
  5. Strings
  6. Ausnahme-Behandlung
  7. Tupel, Listen, Dictionaries, Mengen
  8. Steuerfluss
  9. Funktionen
  10. Ein-/Ausgabe
  11. Start externer Kommandos
  12. Funktionale Programmierung
  13. OOP - Einstieg
  14. OOP - ein etwas komplexeres Beispiel

1. Hello World

  #!/usr/bin/env python
  # -*- coding: utf8 -*-
  
  """
  Hello World: als Modul oder Programm nutzbar
  """
  
  # Definition der parameterlosen Funktion "hello"
  def hello():
    """Funktion hello(): Ausgabe des Strings 'hello world'"""
    print 'hello world'
  
  if __name__ == '__main__':
    # die Funktion "hello" ausführen, da der vorliegende Code als Programm
    # gestartet und nicht als Modul importiert wurde
    hello()

Nutzung des Moduls helloworld.py:

  #!/usr/bin/env python
  # -*- coding: utf8 -*-
  
  import helloworld
  
  # die Funktion "hello" des Moduls "helloworld" aufrufen
  helloworld.hello()
  
  # den DOC-String von "hello" ausgeben
  print helloworld.hello.__doc__
  
  # Funktion help nutzen
  help(helloworld)

2. Programmierparadigmen

  #!/usr/bin/env python
  # -*- coding: utf8 -*-
  #
  # Demonstration von Programmier-Paradigmen
  
  import sys
  
  # Python 2 oder 3?
  python2 = sys.version_info[0] == 2
  
  if python2:
    # das range() von Python 3 heißt bei Python 2 xrange()
    range = xrange
  else:
    # ab Python 3 die Funktion filter() so redefinieren, dass sie immer eine
    # Liste liefert
    def filter(krit, seq):
      return list(__builtins__.filter(krit, seq))
  
  # ========================================
  # OOP - Objektorientierte Programmierung
  # ========================================
  
  print('OOP')
  
  # Filterkriterium: True bei positiven Werten, sonst False
  def positiv(x):
    return x > 0
  
  # Klasse für Sequenzen mit Filter-Funktion
  class filter_seq(object):
    def __init__(self, seq):
      self.seq = seq
  
    def filter(self, krit):
      # Nutzung der eingebauten Standard-Funktion filter();
      # Rekursion unterbleibt, da die Objektmethode filter()
      # mit self.filter() angesprochen werden muss
      return filter(krit, self.seq)
  
  # Objekt der Klasse filter_seq instanziieren
  fs = filter_seq(range(-5, 5))
  
  # für das Objekt die Methode filter aufrufen
  print(fs.filter(positiv))
  
  print('------------')
  
  # ========================================
  # imperative/prozedurale Programmierung
  # ========================================
  
  print('imperativ/prozedural')
  
  # imperativ programmierte Filterfunktion
  def p_filter(krit, seq):
    result = []
    for elem in seq:
      if krit(elem):
        result.append(elem)
    return result
  
  # Anwendung der Filterfunktion auf eine Liste
  print(p_filter(positiv, range(-5, 5)))
  
  print('------------')
  
  # ========================================
  # funktionale (deklarative) Programmierung
  # ========================================
  
  print('funktional')
  
  # Nutzung der eingebauten Funktion filter
  print(filter(positiv, range(-5, 5)))
  
  # dito, aber Nutzung einer anonymen Lambda-Funktion als Kriterium
  print(filter(lambda x: x > 0, range(-5, 5)))
  
  # List Comprehension: Listengenerierung durch funktionalen Ausdruck
  print([2 * x for x in range(-5, 5) if x > 0])
  
  print('------------')
  
  # bei großen Listen empfehlen sich Generatorausdrücke statt List Comprehensions;
  # Generator-Objekt über einen Generatorausdruck erzeugen:
  gen = (2 * x for x in range(-100, 100) if x > 0)
  print(gen)
  
  # durch Iteration über dem Generator die Elemente ausgeben, die kleiner 21 sind
  for x in gen:
    if x > 20:
      break
    print(x)
  
  print('------------')
  
  # den Generator kann man auch ohne Generatorausdruck erstellen:
  def mygen(von, bis):
    x = von if von > 1 else 1
    while x < bis:
      yield 2 * x
      x += 1
      print('back in generator; new x =', x)
  
  # Nutzung des eigenen Generators
  for x in mygen(-100, 100):
    if x > 20:
      break
    print(x)
  
  print('------------')
  
  # ========================================
  # AOP - Aspektorientierte Programmierung
  # ========================================
  
  print('AOP')
  
  # ein Logger-Objekt als Wrapper zur Ergänzung des Aspekts (der
  # Querschnittsaufgabe) "Logging"
  class logger(object):
    def __init__(self, func):
      # Zähler für Anzahl der Funktionsaufrufe nullen
      self.calls = 0
      # die Original-Funktion merken
      self.func = func
  
    def __call__(self, *args):
      # Aufruf-Zähler inkrementieren
      self.calls += 1
      # Logging durchführen
      print('call %s to %s' % (self.calls, self.func.__name__))
      # Aufruf der Original-Funktion
      self.func(*args)
  
  # die Funktion "myfunc" dekorieren und diese so mit dem Wrapper umgeben
  @logger
  def myfunc(*args):
    print(args)
  
  # indirekter Ruf der Funktion "myfunc" über den Logger als Wrapper; dessen
  # Funktion __call__ wird aufgerufen; sie fügt ihre Logging-Logik hinzu und ruft
  # dann die Original-Funktion "myfunc"
  myfunc(1, 3, 7, 9)
  myfunc(*(range(-5, 5)))
  myfunc('x', 'y', 'z')
  myfunc(True, False, None)

3. Zugriff auf Argumenteliste und Umgebung

  #!/usr/bin/env python
  # -*- coding: utf8 -*-
  
  """
  Ausgabe der Argumente-Liste und der Umgebung
  """
  
  import sys, os
  
  # sys.argv ist eine Liste
  print 'Argument-Liste: %s\n' % sys.argv
  
  # os.environ ist ein Dictionary
  # Keys  --> Namen der Umgebungsvariablen
  # Werte --> Inhalte der Umgebungsvariablen
  
  # max. Länge der Keys ermitteln; wir übergeben dazu einen durch einen
  # Generator-Ausdruck erzeugten Generator an die eingebaute Funktion max()
  max_len = max(len(x) for x in os.environ)
  
  # formatierte Ausgabe des Dictionarys
  print 'Umgebung:'              
  for key, value in os.environ.items():
    # bei Python 2 existiert für die Iteration noch os.environ.iteritems(); bei
    # Python 3 wird nur noch os.environ.iter() unterstützt, das aber im Gegensatz
    # zu Python 2 keine Liste mehr liefert, sondern ein iterierbares View-Objekt
    print '  %-*s --> %s' % (max_len, key, value)

4. Rechnen mit Python

  #!/usr/bin/env python
  # -*- coding: utf8 -*-
  
  """
  Rechnen mit Python
  """
  
  # Operator / soll "echte" Division ermöglichen; ab Python 3 ist dies der
  # Standard
  from __future__ import division
  import decimal
  
  # 2 Float-Zahlen von der Standard-Eingabe einlesen
  netto = float(input('Nettopreis: '))
  mwst = float(input('Mehrwertsteuer in %: '))
  
  # Anmerkung: raw_input() statt input() ist analog möglich und potenziell
  # sicherer, da es den gelesenen String nicht als Python-Ausdruck interpretiert,
  # sondern als reinen String liefert.
  # Ab Python 3 existiert nur noch input(), das sich dann aber wie raw_input()
  # verhält.
  #
  # netto = float(raw_input('Nettopreis: '))
  
  brutto = netto * (1 + mwst / 100)
  print
  
  print 'Brutto:', brutto
  print 'Brutto mit 2 Stellen: %.2f' % brutto
  print 'Brutto gerundet auf 3 Stellen: ', round(brutto, 3)
  
  print
  
  print (1 + 011) * 0x0a, 1.35, 1.8E5, (3 + 1j) * 3, 3 ** 4
  print 10 ** 20, 200L
  
  print
  
  print 'Division'
  print 1/3, 1 // 3
  print
  
  a = 12.1
  b = 2
  c = a / b
  print c       # 6.05
  print str(c)  # 6.05
  print repr(c) # 6.0499999999999998
  print `c`     # nur bei Python 2: wie repr(c): 6.0499999999999998
  
  # repr() wird im interaktiven Modus benutzt:
  # >>> 12.1 / 2
  # 6.0499999999999998
  # >>>
  
  a = decimal.Decimal(str(a))
  b = decimal.Decimal(str(b))
  c = a / b
  print repr(c) # Decimal("6.05")
  print c       # 6.05
  print
  
  # die Operationen mit Decimals kann man ziemlich fein über den Context steuern;
  # hier ein Beispiel:
  
  # den Default-Kontext auslesen
  default_context = decimal.getcontext()
  # einen neuen Kontext einstellen, der eine abweichende Präzision aufweist
  decimal.setcontext(decimal.Context(prec = 5))
  
  # in einer Schleife jeweils zwei Zahlenpaare addieren
  for z1, z2 in ('1.11111111', '2.22222222'), ('3.33333333', '4.44444444'):
    a = decimal.Decimal(z1)
    b = decimal.Decimal(z2)
    print a
    print b
    print a + b
    # Achtung: der hier genutzte ternäre Operator existiert erst ab Python 2.5
    print 'gerundet' if decimal.getcontext().flags[decimal.Rounded] else 'exakt'
    # den Default-Kontext wieder aktivieren
    decimal.setcontext(default_context)
  
  # Ausgabe:
  #   1.11111111
  #   2.22222222
  #   3.3333
  #   gerundet
  #   3.33333333
  #   4.44444444
  #   7.77777777
  #   exakt
  

5. Strings

  #!/usr/bin/env python
  # -*- coding: utf8 -*-
  
  """
  Demo zu Python-Strings und regulären Ausdrücken
  """
  
  import sys, re, codecs, os
  
  io_encoding = 'PYTHONIOENCODING' in os.environ
    # Wir vermerken, ob die Umgebungsvariable PYTHONIOENCODING gesetzt ist.
    # 
    # Das Manual von Python 3 sagt zu PYTHONIOENCODING:
    #   If this is set before running the interpreter, it overrides the encoding
    #   used for stdin/stdout/stderr, in the syntax encodingname:errorhandler.
    #   The :errorhandler part is optional and has the same meaning as in
    #   str.encode().
    #
    #   For stderr, the :errorhandler part is ignored; the handler will always be
    #   'backslashreplace'.
    #
    # Das Setzen von PYTHONIOENCODING ist z.B. dann wichtig, wenn die Ausgabe
    # eines Python-Programms in eine Pipe oder eine Datei umgelenkt wird. Ggf.
    # kommt es dabei zu einem Fehler, der nicht auftritt, wenn die Ausgabe auf
    # ein Terminal erfolgt:
    #
    # * Fehlerfreie Ausgabe auf ein UTF8-fähiges Terminal:
    #  
    #     python -c $'# -*- coding: utf8 -*-\nprint u"äöüß"'
    #  
    # * Fehler bei Ausgabeumlenkung in eine Datei oder Pipe:
    #
    #     python -c $'# -*- coding: utf8 -*-\nprint u"äöüß"' > out
    #       Traceback (most recent call last):
    #         File "<string>", line 2, in <module>
    #       UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-7: ordinal not in range(128)
    #
    #     python -c $'# -*- coding: utf8 -*-\nprint u"äöüß"' | wc -l
    #       Traceback (most recent call last):
    #         File "<string>", line 2, in <module>
    #       UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-7: ordinal not in range(128)
    #       0
    # 
    # * Fehlerfreie Ausgabeumlenkung in eine Datei oder Pipe:
    #
    #     PYTHONIOENCODING=utf8 python -c $'# -*- coding: utf8 -*-\nprint u"äöüß"' > out2
    #     PYTHONIOENCODING=utf8 python -c $'# -*- coding: utf8 -*-\nprint u"äöüß"' | wc -l
  
  # Apostroph und Doppel-Apostroph als gleichwertige String-Begrenzer
  s1 = 'abc"\n' "xyz"   # Verkettung zweier String-Konstanten
  s2 = "a'b"
  raw1 = r'\d+'   # entspricht: '\\d+'
  raw2 = r'\d+\\' # entspricht: '\\d+\\\\'
  
  # Achtung: einzelner Backslash darf bei Raw String nicht als letztes Zeichen
  # stehen:
  #   r'\a\' ist also unzulässig
  
  print s1, s2, raw1, raw2
  print ('Hallo' + ' Welt ') * 3
  
  # Strings können mehrzeilig sein
  print '''
    ich
    bin
    mehrzeilig
  '''
  
  # Zeichenketten kann man zeichenweise durchlaufen (Sequenz)
  print
  for char in 'Python':
    print char
  
  # ord()    --> ASCII- bzw. Unicode-Code eines Zeichens bzw. Unicode-Zeichens
  #              ermitteln
  # chr()    --> Zeichen mit angegebenem ASCII-Code generieren
  # unichr() --> Unicode-Zeichen mit angegebenem Code generieren
  print
  p = 'Python' + '%c%c.%c' % (chr(32), chr(0x32), chr(ord('5') + 1))
  print p
  
  # Unicode-Zeichen ä
  if io_encoding:
    print unichr(228), ord(u'ä')
  
  s = 'Guido van Rossum'.upper()
  print '%s, %s' % (s[-10:], s[:5])
  
  # Strings sind unveränderliche Objekte
  #
  # >>> a = 'aaa'
  # >>> a[1] = 'b'
  # Traceback (most recent call last):
  #   File "<stdin>", line 1, in ?
  # TypeError: object does not support item assignment
  
  # Anwendung von String-Funktionen (Methoden von String-Objekten)
  s = s[:5] + ' ' + s[-6:]
  print s.replace(' ROSSUM', '')
  print s
  
  print
  for g in 'Guido van Rossum', 'Guido Westerwelle', 'Heinz':
    if g.endswith('Rossum') and g.startswith('Guido'):
      print g, '--> BDFL'
    elif 'Guido' in g:
      print g, '--> any other Guido'
    else:
      print g, '--> ???'
  
  s = 'Guido van Rossum'
  print
  print '/'.join(s.lower().split())
  
  # Unicode-Strings
  unicode_str = u'äöü\N{Copyright Sign}'
  print 'latin1', unicode_str.encode('latin1')
  print >>sys.stderr, 'utf8', unicode_str.encode('utf8')
  
  if io_encoding:
    # die Original-Standardausgabe sichern
    orig_stdout = sys.stdout
  
    # den StreamWriter des UTF8-Codecs auf stdout anwenden:
    #   >>> c=codecs.lookup('utf8')
    #   >>> c
    #   <codecs.CodecInfo object for encoding utf-8 at 0x98151ac>
    #   >>> list(c)
    #   [<built-in function utf_8_encode>, <function decode at 0xb7c22bec>, <class
    #   'encodings.utf_8.StreamReader'>, <class 'encodings.utf_8.StreamWriter'>]
    sys.stdout = codecs.lookup('utf8')[-1](orig_stdout)
    print 'utf8 via codecs', unicode_str
  
    # die Original-Standardausgabe wiederherstellen
    sys.stdout = orig_stdout
  
  print
  
  # kurzer Blick auf reguläre Ausdrücke
  # (?i)    --> Flag i: ignore case
  # (?=egg) --> lookahead assertion
  muster = re.compile(r'(?i)spam\d+(?=egg)')
  
  s = 'x spaM1eGg spamlegg spam12xyc Spam88EGg spam23'
  print s
  
  # alle Vorkommen des Musters suchen
  print muster.findall(s)
  
  # erstes Vorkommen des Musters suchen
  res = muster.search(s)
  if res:
    print 'gefunden', s[res.start() : res.end()]
  print
  
  # match() sucht das Muster nur am String-Anfang
  s = '# anton=a22 berta=b11 caesar dora='
  res = re.match(r'(\w+)=(\w+)', s)
  print 'match:', res
  
  # search() sucht das Muster irgendwo im String
  res = re.search(r'(\w+)=(\w+)', s)
  if res:
    print 'search:', res.groups()
  
  # Substitution
  print re.sub(r'(\w+)=(\w+)', r'\1:"\2"', s)
  
  # Substitution unter Nutzung einer eigenen Replace-Funktion, die für jedes
  # Match-Objekt gerufen wird; wir wandeln in Ausdrücken der Form "wort=wort" nur
  # das Wort links vom Gleicheitszeichen in Großbuchstaben um; group(0) und
  # group(1) sind hier identisch
  print re.sub(r'(\w+)(?==\w+)', lambda x : x.group(0).upper(), s)
  print re.sub(r'(\w+)(?==\w+)', lambda x : x.group(1).upper(), s)

6. Ausnahme-Behandlung

  # -*- coding: utf8 -*-
  """
  Ausnahmebehandlung (Exception Handling)
  """
  
  import sys
  
  def cat(filename):
    """Ausgabe einer Datei analog Kommando cat"""
    try:
      print open(filename).read(),
    except:
      print 'Kann %s nicht einlesen' % filename
    else:
      print 'Alles OK'
          
  cat('/etc/hosts')
  cat('/etc/hosts1')
        
  # ------------------------
  # try / except / else
  
  print 'try / except / else'
  try:
    a = int(raw_input('Zahl: '))
    if a == 0:
      sys.exit(0)
    if a < 7:
      raise ValueError
  except ValueError:
    print 'Ungueltiger Wert'
  except SystemExit:
    # diese Ausnahme ignorieren
    pass
  except:
    # sonstige Ausnahme erneut auswerfen
    raise
  else:
    # keine Ausnahme aufgetreten
    print 'Alles OK:', a
  
  # ------------------------
  # try / finally
  print 'try / finally'
  for i in 1, 0:
    try:
      try:
        x = 1 / i
      finally:
        # finally wird immer ausgeführt und ist für Aufräumarbeiten gedacht;
        # eine aufgetretene Ausnahme wird nach finally erneut ausgeworfen
        print 'Division beendet'
      print x
    except:
      print 'Ausnahme %s, %s' % sys.exc_info()[:2]
  
  # ------------------------
  # try / except / finally
  print 'try / except / finally'
  for i in 1, 0:
    try:
      x = 1 / i
    except Exception, e:
      print 'Ausnahme %s, %s' % (type(e), e)
    finally:
      # finally wird immer ausgeführt und ist für Aufräumarbeiten gedacht;
      # eine aufgetretene Ausnahme wird nach finally erneut ausgeworfen
      print 'Division beendet'
    print x

7. Tupel, Listen, Dictionaries, Mengen

  #!/usr/bin/env python
  # -*- coding: utf8 -*-
  
  """
  Demo zu den Collection Types Tupel, Liste, Dictionary und Menge
  """
  
  import sys
  python2 = sys.version_info[0] == 2
  
  # Tupel
  print 'Tupel'
  
  # einelementiges Tupel mit Komma am Ende
  tupel1 = 1,
  print tupel1
  
  # mehrelementiges Tupel
  tupel = 1, 2, 3
  
  for i in 1, 2, 3: print i
  print
  
  # explizite Tupel-Klammerung generell möglich, aber bei Tupel-Zuweisungen und
  # Schleifen nicht nötig
  tupel1 = (1,)
  tupel = (1, 2, 3)
  for i in (1, 2, 3): print i
  print
  
  print tupel[0:2]
  a, b, c = tupel
  for i in tupel:
    print i
  print tupel + tupel, tupel * 2
  print tupel + tuple('abcd') + tuple([1, 2, 3])
  
  # hier ist eine explizite Klammerung nötig:
  print '%d %d %d' % (1, 2, 3)
  
  # Listen
  print '\nListen'
  liste = [1, 'abc', 2.3, 4l, (1, 2), {1: 2}, [5, 6, 7]]
  print liste
  for elem in liste:
    print type(elem), elem
  
  print
  # erstes Listenelement löschen
  del liste[0]
  for pos, elem in enumerate(liste):
    print pos, elem
  
  print
  # die ersten 10 Zeilen von /etc/passwd in umgekehrter Reihenfolge durchlaufen
  for line in reversed(open('/etc/passwd').readlines()[:10]):
    # die Felder in umgekehrter Reihenfolge zusammensetzen und ausgeben
    print ':'.join(reversed(line.rstrip('\r\n').split(':')))
  
  print
  
  print 'Listen als Stacks und Queues'
  print liste
  print 'pop(3)'
  print liste.pop(3)
  print liste
  print 'append(25)'
  liste.append(25)
  print liste, len(liste)
  
  stack = [1, 2, 3]
  # queue durch Slicing als Kopie von Stack anlegen
  queue = stack[:]
  
  # für push und pop gebundene Methoden der Listen-Klasse verwenden
  push = stack.append
  pop = stack.pop
  
  print '\nStack'
  push(4); print stack
  push(5); print stack
  while stack:
    el = pop()
    print el, ',', stack
  
  print '\nQueue'
  enqueue = queue.append
  dequeue = lambda: queue.pop(0)
  enqueue(4); print queue
  enqueue(5); print queue
  while queue:
    el = dequeue()
    print el, ',', queue
  
  # Dictionaries
  print '\nDictionaries'
  d = {'Anton': 34, 'Berta': 19, 'Cäsar': 45, 'Alfred': 88, 'Bianca': 11}
  
  print '\nsortierte Schlüssel'
  print sorted(d.keys())
  print sorted(d)
  
  print '\nsortierte Werte'
  print sorted(d.values())
  
  print '\numgekehrt sortierte Werte'
  print sorted(d.values(), reverse = True)
  print list(reversed(sorted(d.values())))
  
  print '\nPaare'
  for key, value in d.iteritems() if python2 else d.items():
    print key, value
  print
  
  print d['Anton']
  del d['Anton']
  d['Alfred'] += 10
  d.update(Marta = 23, Emma = 77)
  d = dict(d, Otto = 88, Adam = 43)
  d.update([('Jutta', 44), ('Jens', 17)])
  
  print '\n', d
  for name in 'Anton', 'Emma', 'Jörg':
    print name, name in d
  
  # Mengen
  print '\nMengen'
  set1 = set('abcdax')  
  set2 = frozenset((1, 2, 3, 1, 'b'))  
  print 'set1:', set1 
  print 'set2:', set2 
  print 'Vereinigung:', set1 | set2, set1.union(set2)
  print 'Differenz:', set1 - set2, set1.difference(set2)
  print 'Schnittmenge:', set1 & set2, set1.intersection(set2)
  # hier noch die symmetrische Differenz, also die Differenz aus
  # Vereinigungsmenge und Schnittmenge bilden
  print 'Symmetrische Differenz:', set1 ^ set2, set1.symmetric_difference(set2)
  set1.add(45)
  set1.remove('x')
  print 'set1:', set1

8. Steuerfluss

  #!/usr/bin/env python
  # -*- coding: utf8 -*-
  
  """
  Demo zu den Steuerfluss-Anweisungen von Python
  """
  
  import sys
  
  print 'Zeilen von stdin laut Länge klassifizieren'
  
  for line in sys.stdin:
    # \r und \n am String-Ende streichen
    line = line.rstrip('\r\n')
    # alle White-Spaces am Anfang und Ende des Strings streichen
    l = line.strip()
  
    if l == '' or l.startswith('#'):
      # Zeile ist leer oder Kommentar --> übergehen
      continue
  
    # Zeile nach der Länge klassifizieren
    l = len(line)
    if l < 10:
      print 'kurz', line
    elif l > 40:
      print 'lang', line
    else:
      print 'mittel', line
  
  print '---------------'
  
  print 'Integers eines Intervalls in zwei Integer-Faktoren zerlegen'
    
  # for mit else
  
  for n in range(2, 10):
    # Zahl n durchläuft das gewünschte Intervall
    for x in range(2, n):
      # x durchläuft alle möglichen ganzzahligen Faktoren
      if n % x == 0:
        # x teilt n ohne Rest und ist somit ein Faktor
        print n, 'gleich', x, '*', n/x
        break
    else:
      # reguläres Schleifenende erreicht --> kein Faktor ermittelt
      print n, 'ist eine Primzahl'
  
  # pass -- leere Anweisung
  if len(sys.argv) > 1:
    # muss noch implementiert werden
    pass

9. Funktionen

  #!/usr/bin/env python
  # -*- coding: utf8 -*-
  
  """
  Demo zu Python-Funktionen
  """
  
  from math import pi
  
  def fib(n = 5):
    """
    Folge der Fibonacci-Zahlen bis Zahl n ermitteln:
      a1 = 0
      a2 = 1
      an = an-2 + an-1 für n > 2
    """
    result = []
    # zwei Variablen, die die jeweils letzten beiden Elemente der Fibonacci-Folge
    # enthalten; die Initialbelegung mit 1, 0 sichert, dass wir die Sonderfälle
    # a1 und a2 ganz regulär mit behandeln können
    an_minus_1, a_n = 1, 0
    # in einer Schleife n Fibonacci-Zahlen generieren
    for i in range(n):
      # aktuelles a_n an die Resultat-Liste anhängen
      result.append(a_n)
      # aus den aktuellen letzten beiden Elementen wird die nachfolgende Zahl der
      # Folge berechnet; die beiden Variablen werden durch zyklische Verschiebung
      # aktualisiert
      an_minus_1, a_n = a_n, an_minus_1 + a_n
    return result
  
  print 'fib(10)', fib(10)
  print 'fib()', fib()
  print 'fib(0)', fib(0)
  print 'fib(1)', fib(1)
  print 'fib(2)', fib(2)
  
  def to_upper(liste):
    """alle Strings einer Liste in Großbuchstaben umwandeln"""
    for i in range(len(liste)):
      try:
        liste[i] = liste[i].upper()
      except:
        # offenbar kein String
        pass
  
  print
  l = ['anton', 1, 'berta']
  to_upper(l)
  print l
  
  def make_unique(liste, keep = True):
    """alle mehrfach vorkommenden Listen-Elemente streichen"""
    if keep:
      # beim Streichen der Dubletten verändern wir die ursprüngliche Reihenfolge
      # der verbleibenden Elemente nicht
      result = []
      for elem in liste:
        if elem not in result:
          result.append(elem)
      # die alte durch die neue Liste komplett ersetzen
      liste[:] = result
    else:
      # Element-Reihenfolge spielt keine Rolle: Liste in eine Menge umwandeln,
      # dadurch die Dubletten eliminieren; anschließend die Menge wieder in eine
      # Liste konvertieren; durch den Slicing-Ausdruck ":" manipulieren wir die
      # Liste, die der Funktion als Argument übergeben wurde; sie wird komplett
      # durch die neue Liste ohne Dubletten ersetzt
      liste[:] = list(frozenset(liste))
  
  print
  l = [1, 8, 1, 2, 9, 2, 7, 2, 3, 7]
  m = l[:]
  make_unique(l)
  print l
  make_unique(m, False)
  print m
  
  def kreis(radius = None, durchmesser = None):
    """
    Kreisumfang und -fläche berechnen
  
    Rückgabe: Tupel aus Umfang, Fläche, Fehlermeldung
    """
    eps = 1e-10
    if radius is durchmesser is None:
      return (None, None, 'Radius und Durchmesser nicht spezifiziert!')
    elif radius != None and durchmesser != None and abs(durchmesser - 2 * radius) > eps:
      return (None, None, 'Radius und Durchmesser passen nicht zusammen!')
    elif durchmesser is None:
      # Durchmesser aus Radius berechnen
      durchmesser = 2 * radius
    return (pi * durchmesser, pi / 4 * durchmesser ** 2, '')
  
  print
  print 'Kreisberechnnung: Umfang, Fläche, ggf. Fehlermeldung'
  for expr in ['kreis(radius = 3)',
               'kreis(3)',
               'kreis(durchmesser = 6)',
               'kreis(3, 6)',
               'kreis(3, 6.001)',
               'kreis()']:
    print expr, '-->', eval(expr)

10. Ein-/Ausgabe

  #!/usr/bin/env python
  # -*- coding: utf8 -*-
  
  """
  Demo der Ein-/Ausgabe mit und ohne Formatierung
  """
  
  import sys
  
  # Ausgabe nach stdout
  print 1, 2, 'hallo'
  
  # ohne Zeilenschaltung am Ende durch abschließendes Komma
  print 'Hallo',
  # mit Zeilenschaltung am Ende
  print 'Leute'
  
  # Ausgabe nach stderr
  print >>sys.stderr, 'Fehler'
  
  # zeilenweise von stdin lesen
  print 'zeilenweise von stdin lesen'
  for line in sys.stdin:
    print line,
  
  # ältere Variante:
  print 'nochmal zeilenweise von stdin lesen'
  while 1:
    line = sys.stdin.readline()
    if line == '':
      break
    print line,
  
  print '==='
  
  # File zum Lesen öffnen;
  # statt "open(...)" kann man bei Python 2.X auch "file(...)" schreiben 
  f = open('/etc/hosts')
  
  # File geschlossen einlesen
  inhalt = f.read()
  f.seek(0)
  zeilen_liste = f.readlines()
  print inhalt
  print zeilen_liste
  print
  
  # File kopieren
  out = open('/tmp/hosts_dos', 'w')
  for line in open('/etc/hosts'):
    # im DOS-Format speichern
    print >>out, line.rstrip('\n') + '\r'
  # File schließen
  out.close()
  
  # noch eine Kopie im Unix-Format anlegen
  out = open('/tmp/hosts_unix', 'w')
  for line in open('/tmp/hosts_dos', 'U'):
    # durch den Universal Newline Mode (U) stellt Python die gelesenen Zeilen
    # automatisch im UNIX-Format bereit
    out.write(line)
  out.close()
  
  # Formatierung mit %
  for i in range(10):
    print '%10d, %10d' % (i, 2 * i) 
  print
  
  # die Werte aus einem Dictionary nehmen
  d = { 'Anton': 10, 'Berta' : 20, 'Cäsar' : 30 }
  print '%(Anton)d, %(Berta)d, %(Cäsar)d' % d
  print
  
  # die Funktionen zfill() und rjust() nutzen
  for i in range(10):
    print str(i).zfill(10)
  print
  
  for i in range(10):
    print str(i).rjust(20)

11. Start externer Kommandos

  #!/usr/bin/env python
  # -*- coding: utf8 -*-
  
  """
  Aufruf externer Programme aus Python-Programmen
  """
  
  import sys, os, tempfile, subprocess
  
  class MyError(Exception):
    """eigene Exception-Klasse"""
    def __init__(self, value = ''):
      Exception.__init__(self, value)
  
  def make_temp_file():
    """sichere Erzeugung eines temporären Files"""
    if 'mkstemp' in dir(tempfile):
      # mkstemp() steht zur Verfügung (ab Python 2.3); dann nutzen wir es;
      # es liefert ein Tupel aus File Descriptor und File-Name; wir benötigen den
      # Namen; den Descriptor schließen wir
      fd, name = tempfile.mkstemp('', 'PYTMP.', '/tmp')
      os.close(fd)
      return name
    else:
      # mkstemp() steht nicht zur Verfügung; dann nutzen wir das
      # Unix-Standard-Tool mktemp über eine Pipe
      data = os.popen('mktemp /tmp/PYTMP.XXXXXXXX 2>/dev/null').readlines()
      if not data:
        # leerer Datei-Name --> Fehler
        raise MyError, 'Fehler beim Anlegen einer temporären Datei'
      # den Namen der temporären Datei zurückgeben
      return data[0].strip()
  
  def quote_shell_args(s):
    """
    einen String so quotieren, dass man ihn literal als Wort an ein
    Bourne-Shell-Skript übergeben kann
    """
    return "'" + s.replace("'", r"'\''") + "'"
  
  def run_external_command(*cmd_words):
    """externes Kommando über eine Bourne-Shell ausführen"""
    try:
      # Aufruf des Shell-Kommandos vorbereiten;
      # zuerst einen temporären Dateinamen für die Kommunikation mit dem
      # Shell-Skript generieren
      tfile = make_temp_file()
  
      # den Kommando-String generieren
      cmd = []
      for word in cmd_words:
        cmd.append(quote_shell_args(str(word)))
      cmd.append('> %s 2>&1' % tfile)
      cmd = ' '.join(cmd)
  
      # Skript ausführen
      if os.system(cmd):
        # system() hat einen Fehler gemeldet; wir melden ihn über die Ausnahme
        # MyError
        raise MyError, 'Fehler beim Ausführen des externen Skripts ' + cmd
  
      # Ausgabe des Skripts zurücklesen und zurückgeben; das temporäre File wird
      # hier gleich mit gelöscht
      result = open(tfile).readlines()
      os.unlink(tfile)
      return result
    except MyError:
      # eine MyError-Ausnahme werfen wir unverändert wieder aus
      raise
    except:
      # alle anderen Ausnahmen werfen wir als MyError-Ausnahme aus
      raise MyError, 'Ausnahme: %s/%s' % (sys.exc_info()[0], sys.exc_info()[1])
  
  # Start eines externen Kommandos via Shell
  os.system('date')
  print
  
  # externes Shell-Kommando starten und das Ergebnis über eine Pipe zurücklesen
  for line in os.popen('cal 6 2009 2>&1'):
    print line,
  
  # Implementierung mit dem neuen Modul subprocess statt os.system (ab Python
  # 2.4):
  for cmd in ('cal', '7', '2006'), ('rm', '/'), 'date1':
    try:
      status = subprocess.call(cmd)
      if status:
        print 'Fehler; Exit-Code:', status
    except:
      print 'Ausnahme: %s/%s' % (sys.exc_info()[0], sys.exc_info()[1])
    print
  
  # Nutzung der eigenen Funktion run_external_command
  for cmd in ('cal', 7, 2006), ('cal1', 7, 2006):
    try:
      for line in run_external_command(*cmd):
        print line,
      print
    except MyError, obj:
      print obj.args[0], '\n'
  
  # bidirektionale Kommunikation mit einem externen Kommando
  subp = subprocess.Popen('touch /tmp/aaa ; rm -v /tmp/aaa / ; tr a-z A-Z',
                          # line buffered
                          bufsize = 1,
                          # das Kommando an die Shell zur Ausführung übergeben
                          shell = True,
                          # über eine Pipe kommunizieren
                          stdin = subprocess.PIPE,
                          stdout = subprocess.PIPE,
                          stderr = subprocess.PIPE
                          )
  s = 'aaa\nbbb\nccc'
  stdout, stderr = subp.communicate(s)
  print 'gesendet:', s
  print 'stdout:', stdout
  print 'stderr:', stderr

12. Funktionale Programmierung

  #!/usr/bin/env python
  # -*- coding: utf8 -*-
  
  """
  Demo zu filter(), map(), reduce(), lambda
  List Comprehensions
  Generator-Ausdrücke
  """
  
  import operator
  from math import pi, sin
  
  # filter(), map(), reduce()
  
  print 'Liste der nicht durch 2 und 3 teilbaren ganzen Zahlen zwischen 2 und 24'
  def f(x): return x % 2 != 0 and x % 3 != 0
  print filter(f, range(2, 25))
  print
  
  print 'Liste der dritten Potenzen der ganzen Zahlen von 1 bis 10'
  def cube(x): return x ** 3
  print map(cube, range(1, 11))
  print
  
  print 'Liste der Produkte der korrespondierenden Elemente der Intervalle [1, 7] und [7, 1]'
  seq = range(1, 8)
  def mul(x, y): return x * y
  print map(mul, seq, reversed(seq))
  print
  
  print 'Summe der ganzen Zahlen von 1 bis 10'
  def add(x, y): return x + y
  print reduce(add, range(1, 11))
  print
  
  print 'Summe einer Zahlenfolge'
  def mysum(seq):
    def add(x, y): return x + y
    # hier mit Start-Wert 0, so dass wir auch leere Sequenzen verarbeiten können
    return reduce(add, seq, 0)
  print mysum(range(1, 11)), mysum([])
  print
  
  print 'bessere Implementierung durch Nutzung der eingebauten Funktion sum()'
  print sum(range(1, 11)), sum([])
  print
  
  # Currying (partial function application): bestimmte Argumente an eine Funktion
  # binden
  
  # mit Closure: innere Funktion, die auf lokale Namen einer äußeren Funktion
  # Bezug nimmt
  print 'add3 mit Closure'
  def make_adder(n):
    def adder(x):
      #return operator.add(x, n)
      return x + n
    return adder
  
  add3 = make_adder(3)
  print add3(1)
  
  # mit lambda: anonyme Funktion
  print 'add3 mit lambda'
  #add3 = lambda x: operator.add(x, 3)
  add3 = lambda x: x + 3
  print add3(1)
  
  # mit rufbarer Klassen-Instanz
  print 'add3 mit rufbarer Klassen-Instanz'
  class make_adder_class(object):
    def __init__(self, n):
      self.n = n
    def __call__(self, x):
      return x + self.n
  
  add3 = make_adder_class(3)
  print add3(1)
  
  # List Comprehensions
  
  print 'List Comprehensions'
  freshfruit = ['  banana', '  loganberry ', 'passion fruit  ']
  print [fruit.strip() for fruit in freshfruit]
  print
  
  vec = [2, 4, 6]
  print [3 * x for x in vec]
  print [3 * x for x in vec if x > 3]
  print [3 * x for x in vec if x < 2]
  print [(x, x ** 2) for x in vec]
  print
  
  vec1 = [2, 4, 6]
  vec2 = [4, 3, -9]
  print [x * y for x in vec1 for y in vec2]
  print [x + y for x in vec1 for y in vec2]
  print [vec1[i] * vec2[i] for i in range(len(vec1))]
  print
  
  # Pi auf eine steigende Zahl von Stellen runden
  print [str(round(pi, i)) for i in range(1, 10)]
  print
  
  # Generator-Ausdrücke
  
  print 'Generator-Ausdrücke'
  print
  
  print 'Summe der Quadratzahlen'
  print sum(i ** 2 for i in range(10))
  print
  
  print 'Skalarprodukt zweier Vektoren'
  xvec = [10, 20, 30]
  yvec = [7, 5, 3]
  print sum(x * y for x, y in zip(xvec, yvec))
  print
  
  print 'Tabelle der Sinus-Funktion'
  print dict((x, sin(x * pi / 180)) for x in range(0, 31))
  print
  
  print 'Menge der Wörter eines Textes'
  print set(word for line in open('/etc/hosts') for word in line.split())
  print
  
  print 'maximales Element einer Personen-Liste bestimmen'
  class Person(object):
    def __init__(self, alter, groesse):
      self.alter = alter
      self.groesse = groesse
  
  personen = [ Person(39, 172), Person(88, 165), Person(15, 181), Person(88, 175)]
  print max((person.alter, person.groesse) for person in personen)
  print
  
  print 'Zeichenfolge eines Strings umkehren und als Liste liefern'
  data = 'golf'
  print list(data[i] for i in range(len(data)-1, -1, -1))
  
  # einfachere Implementierung ohne Generator-Ausdruck
  print list(reversed(data))
  
  # oder mit Slicing
  print list(data[::-1])

13. OOP - Einstieg

  #!/usr/bin/env python
  # -*- coding: utf8 -*-
  
  # Klasse mit Klassen- und Instanzvariablen sowie Name Mangling für __name
  class mytest(object):
    # 4 Klassenvariablen erzeugen
    a = 5
    b = a + 5
    __c = 9 * a
    __d__= __c + a
    # im Klassenkörper, aber außerhalb der Funktionen ist der Klassenname
    # unbekannt; die Anweisung
    #   b = mytest.a + 5
    # funktioniert daher nicht
  
    # Konstruktor / Initialisierer
    def __init__(self):
      # Instanzvariable x generieren
      self.x = 99
  
    def myprint(self):
      # Zugriff auf die globalen Variablen a, b, _mytest__c, __d__
      print a, b, __c, __d__
  
      # Zugriff auf die Klassenvariablen über die Instanz (self)
      print self.a, self.b, self.__c, self.__d__
  
      # dito über den Klassennamen, der innerhalb einer Funktion bekannt ist
      print mytest.a, mytest.b, mytest.__c, mytest.__d__
  
      # Zugriff auf die Instanzvariablen x und y
      print self.x, self.y
  
  # 4 globale Variablen mit denselben Namen wie die Klassenvariablen anlegen
  a = 1
  b = 2
  _mytest__c = 3
  __d__ = 4
  
  # Instanz von mytest anlegen 
  m = mytest()
  
  # Instanzvariable y anlegen
  m.y = 100
  
  # Instanzvariable __z anlegen
  m.__z = 200
  
  # Zugriff auf die Variablen; Python kennt nur öffentliche Attribute und daher
  # keine Sprachmittel zur Steuerung der Sichtbarkeit (z.B. public, private,
  # protected, ...)
  print m.a
  print m.b
  print m._mytest__c
  print m.__d__
  print m.x
  print m.y
  print m.__z
  m.myprint()
  
  # die Klassenvariable a mit einem neuen Wert belegen; das geht nur über die
  # Klasse und nicht über die Instanz, also nicht über m.a
  mytest.a = 1000
  print mytest.a
  
  # 2. Instanz erzeugen
  m2 = mytest()
  # darüber Zugriff auf die Klassenvariable a
  print m2.a

14. OOP - ein etwas komplexeres Beispiel

Modul BankKonto:

  #!/usr/bin/env python
  # -*- coding: utf8 -*-
  
  """
  OOP-Demo am Beispiel eines gebührenfreien und gebührenpflichtigen Bankkontos
  
  Idee: s. Tutorial "Programmieren lernen" von Alan Gauld
  """
  
  from decimal import Decimal
  
  class SaldoError(Exception):
    """spezielle Ausnahme für Bankkonten-Operationen"""
  
    def __init__(self, saldo):
      Exception.__init__(self, 'Entschuldigung, Sie haben nur %6.2f EUR auf Ihrem Konto' % saldo)
    
  class BankKonto(object):
    """Realisierung eines gebührenfreien Bankkontos"""
  
    def __init__(self, initialBetrag = 0):
      """Konstruktor"""
      # Saldo wird im Attribut "__saldo" gespeichert; wegen der 2 Unterstriche
      # erfolgt ein "name mangling", also eine automatische Umbenennung zu
      # "_BankKonto__saldo"
      self.__saldo = Decimal(str(initialBetrag))
      # anz_buchungen unterliegt keinem "name mangling"
      self.anz_buchungen = 0
      print 'Konto erzeugt mit Saldo von %6.2f' % self.__saldo
  
    def buchung(self, betrag):
      """eine Buchung (Ein-/Auszahlung) vornehmen"""
      betrag = Decimal(str(betrag))
      self.anz_buchungen += 1
      if betrag >= 0:
        # nichtnegativer Betrag --> Einzahlung
        self.__saldo += betrag
      else:
        # negativer Betrag --> Auszahlung
        if self.__saldo >= abs(betrag):
          self.__saldo += betrag
        else:
          raise SaldoError, self.__saldo
  
    def __iadd__(self, betrag):
      """Überladung des Operators +="""
      self.buchung(betrag)
      return self
  
    def __isub__(self, betrag):
      """Überladung des Operators -="""
      return self.__iadd__(-betrag)
  
    def __str__(self):
      """Überladung von str()"""
      return '%6.2f' % self.__saldo
  
    def __repr__(self):
      """Überladung von repr()"""
      return self.__str__()
  
    def kontostand(self):
      """Abfrage Kontostand"""
      return self.__str__()
       
    def transfer(self, betrag, konto):
      """Transfer auf ein anderes Konto"""
      try: 
        # Betrag vom Saldo des aktuellen Kontos subtrahieren
        self -= betrag
        # und dann zum Saldo des anderen Kontos addieren
        konto += betrag
      except SaldoError, obj:
        # wenn ein SaldoError ausgeworfen wurde, dann schlug die Subtraktion
        # fehl; sie wurde daher zusammen mit der nachfolgenden Addition nicht
        # ausgeführt
        print obj.args[0]
  
  class KostenKonto(BankKonto):
    """von BankKonto abgeleitete Klasse für ein gebührenpflichtiges Konto"""
  
    def __init__(self, initialBetrag = 0, gebuehr = 0.05):
      """Konstruktor; überschreibt die entsprechende Methode der Basisklasse"""
      # Konstruktor der Superklasse rufen
      super(KostenKonto, self).__init__(initialBetrag)
      # die Gebühr in der Property "gebuehr" unter Verwendung der entsprechenden
      # Set-Methode speichern
      self.gebuehr = Decimal(str(gebuehr))
  
    def buchung(self, betrag):
      """erweiterte Buchungs-Methode; überschreibt die entsprechende Methode der Basisklasse"""
      print 'buchung in KostenKonto'
      # Direktzugriff auf die Gebühr unter Umgehung der Get-Methode der Property
      super(KostenKonto, self).buchung(betrag - self.__gebuehr)
  
    def get_geb(self):
      """Implementierung der Property-Methode __get__(): Ermittlung der eingestellten Gebühr"""
      print 'hole Gebühr'
      return self.__gebuehr
  
    def set_geb(self, geb):
      """Implementierung der Property-Methode __set__(): Setzen einer neuen Gebühr"""
      self.__gebuehr = Decimal(str(geb))
      print 'neue Gebühr gesetzt:', geb
  
    def del_geb(self):
      """Implementierung der Property-Methode __delete__(): Löschen der Gebühr"""
      print 'Gebühr kann nicht gelöscht werden'
  
    # die Gebühr als Property definieren;
    # Zugriffe der Art obj.gebuehr nutzen dann die Property-Methoden, Zugriffe
    # der Art self.__gebuehr und obj._KostenKonto__gebuehr dagegen nicht
    gebuehr = property(get_geb, set_geb, del_geb, 'property gebuehr')

Nutzung des Moduls BankKonto:

  #!/usr/bin/env python
  # -*- coding: utf8 -*-
  
  """
  Demo zur Nutzung der Klassen des Moduls BankKonto
  """
  
  from BankKonto import *
  
  print 'erzeuge b mit Initialbetrag 500 und k mit Initialbetrag 0 und Gebühr 0.03'
  b = BankKonto(500)
  k = KostenKonto(gebuehr = 0.03)
  
  # die Kontenobjekte mit dir() und vars() analysieren
  print
  print 'dir(b)'
  print dir(b)
  print
  print 'vars(b)'
  print vars(b)
  print vars(b) is b.__dict__
  print
  print 'dir(k)'
  print dir(k)
  print
  print 'vars(k)'
  print vars(k)
  print vars(k) is k.__dict__
  print
  
  print 'Kontostände'
  print 'b', b, b.kontostand()
  print 'k', k, k.kontostand()
  print
  
  for betrag in 100, 600:
    print 'Transfer %6.2f von b nach k' % betrag
    b.transfer(betrag, k)
    print 'b, k', b, k
    print
  
  for i in range(2):
    print '50 abheben von b und k'
    for varname in 'b', 'k':
      try:
        var = vars()[varname]
        var -= 50
        print varname, var
      except SaldoError, obj:
        print 'Fehlschlag:', obj.args[0]
  print
  
  print '300 einzahlen auf k'
  k += 300
  print k
  print
  
  print 'b._BankKonto__saldo', b._BankKonto__saldo
  print 'k._KostenKonto__gebuehr', k._KostenKonto__gebuehr
  print 'b.anz_buchungen', b.anz_buchungen
  print 'k.gebuehr', k.gebuehr
  k.gebuehr = 0.04
  print 'k.gebuehr', k.gebuehr
  
  del k.gebuehr

8. Namensräume und Sichtbarkeitsbereiche

Praktisches Beispiel vor der Theorie:

  """
  Nested Scopes
  
  Ausgabe:
    inner():
    x in inner
    global x in module
    y in outer
    global set by inner()
    __main__
    -------------------------
    outer():
    x in outer
    global x in module
    y in outer
    global set by inner()
    __main__
    -------------------------
    main():
    global x in module
    global x in module
    y
    global set by inner()
    __main__
  """
  
  x = 'global x in module'
  y = 'y'
  z = 'z'
    
  def outer():
    """aeussere Funktion"""
    x = 'x in outer'
    y = 'y in outer'
  
    def inner():
      """innere Funktion"""
      global z
      x = 'x in inner'
      z = 'global set by inner()'
      print 'inner():'
      print x
      print globals()['x']
      print y
      print z
      print __name__
      print '-------------------------'
  
    inner()
    print 'outer():'
    print x
    print globals()['x']
    print y
    print z
    print __name__
    print '-------------------------'
  
  outer()
  print 'main():'
  print x
  print globals()['x']
  print y
  print z
  print __name__

Namensraum (namespace)

Sichtbarkeitsbereich (scope)


9. Funktionen


10. Objekt-Orientierung


11. Sammlung von Code-Beispielen


12. Links und Literatur zu Python

Einstiegs-Punkte:

Python-Implementierungen:

Sammlungen von Python-Software:

freie Editoren, Shells und integrierte Entwicklungsumgebungen (IDEs)

Python-Bücher im Bestand der UB Chemnitz:

Links zu Kursen, Open Books, Tutorials, FAQs:

Web-Seiten zu einigen Python-Büchern:


Holger Trapp

letzte Modifikation: 10.06.2011