Python

Ein kurzer Vortrag

Einige Fakten

Guido van Rossum

  • Erfinder: Guido van Rossum
  • Erste Version: Anfangs 1990
  • Lizenz: Opensource, PSFL

Einige Datentypen

Listen

>>> a = ['spam', 'eggs', 100, 1234]
>>> a
['spam', 'eggs', 100, 1234]
>>> a[0]
'spam'
>>> a[3]
1234
>>> a[-2]
100
>>> a[2] = a[2] + 23
>>> a
['spam', 'eggs', 123, 1234]

Dictonaries

>>> tel = {'paul':57757, 'barbara':45304}
>>> tel['guido'] = 89003
>>> tel
{'barbara': 45304, 'guido': 89003, 'paul': 57757}
>>> tel['barbara']
45304
>>> tel.keys()
['paul', 'barbara', 'guido']
>>> 'guido' in tel
True                        

Sets

>>> korb = ['Apfel', 'Orange', 'Apfel', 'Birne', 'Orange', 'Banane']
>>> frucht = set(korb)
>>> frucht
set(['Apfel', 'Banane', 'Birne', 'Orange'])
>>> 'Orange' in frucht
True
>>> 'Kiwi' in frucht
False

Sets zum zweiten

So macht Mengenlehre Spass...

>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a        # Buchstaben in a
set(['a', 'r', 'b', 'c', 'd'])
>>> a - b    # ... die es in a gibt aber nicht in b
set(['r', 'd', 'b'])
>>> a | b    # ... von a und b
set(['a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'])
>>> a & b    # ... die in beiden vorhanden sind
set(['a', 'c'])
>>> a ^ b    # ... in a oder b, aber nicht in beiden
set(['r', 'd', 'b', 'm', 'z', 'l'])

Python Stärken

  • Anfängerfreundlich, aber kein Spielzeug
  • Batterien inbegriffen
  • Objektorientiert
  • Interaktiv
  • Rapidprototyping
  • Embeddable
  • Portierbar
  • Schnittstellen zu: C, C++, Objectiv-C, COM, DCOM, Java, .Net, ...

Python Schwächen

  • Performance
  • GIL
  • Python 2 vs. Python 3

Software Entwicklungsprozess

  1. Mach, dass es korrekt läuft
  2. Teste ob es richtig läuft
  3. Läuft es schnell genug?
  4. Falls nicht: Optimieren
  5. Zurück zum zweiten Punkt

Fibonacci

Die Fibonacci-Folge lautet:

  • Die erste Zahl ist 0
  • Die zweite Zahl ist 1
  • Jede weitere Zahl ist die Summe ihrer beiden Vorgänger
#!/usr/bin/env python
# -*- coding: utf-8 -*-

def fib(n):
    if n == 0: return 0
    if n == 1: return 1
    return fib(n - 1) + fib(n - 2)

print fib(10)
$ python fib.py
55
$ chmod +x fib.py
$ ./fib.py
55

Tests mit Doctest

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def fib(n):
    """Berechnet die n-te Zahl der Fibonacci-Folge
    
    >>> fib(0)
    0
    >>> fib(1)
    1
    >>> fib(10)
    55
    """
    if n == 0: return 0
    if n == 1: return 1
    return fib(n - 1) + fib(n - 2)

print fib(10)
$ python -m doctest -v fib.py
Trying:
    fib(0)
Expecting:
    0
ok
...
3 passed and 0 failed.
Test passed.

Performance

Der selbe Code, aber diesmal berechnen wir fib(30).

Um die Zeit zu messen starten wir das Programm mit dem Profiler.

$ python -m cProfile fib.py
832040
         2692539 function calls ... in 9.859 seconds

...

Sehr langsam. Fast 10 Sekunden für die 30-igte Fibonacci Zahl!

Performance verbessern per C-Extension

Fibonacci in C implementiert:

long fib(int);

long fib(int n) {
    if (n == 0) return 0;
    if (n == 1) return 1;
    return fib(n - 1) + fib(n - 2);
}

Als Library kompilieren:

$ gcc -shared -Wl,-soname,libfib -o libfib.so -fPIC libfib.c
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Berechnet die n-te Zahl der Fibonacci-Folge

>>> lib.fib(0)
0
>>> lib.fib(1)
1
>>> lib.fib(10)
55
"""

import ctypes
lib = ctypes.CDLL('./libfib.so')

print lib.fib(30)

Super Schnell: nur noch 0.065
Aber was ist mit grösseren Fibonacci zahlen?

Tipp: Schon im ersten Programm steckt der Wurm drinn.

Profiling des Algorithmus

Wieso ist der Code so langsam bei grösseren Zahlen? Eine einfache Analyse.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def fib(n):
    "..."
    print "fib wurde mit n =", n, "aufgerufen"
    if n == 0: return 0
    if n == 1: return 1
    result = fib(n - 1) + fib(n - 2)
    return result
    
fib(10)
$ python fib.py 
fib wurde mit n = 10 aufgerufen
fib wurde mit n = 9 aufgerufen
fib wurde mit n = 8 aufgerufen
fib wurde mit n = 7 aufgerufen
...
fib wurde mit n = 0 aufgerufen
fib wurde mit n = 1 aufgerufen
fib wurde mit n = 4 aufgerufen
fib wurde mit n = 3 aufgerufen
fib wurde mit n = 2 aufgerufen
fib wurde mit n = 1 aufgerufen
fib wurde mit n = 0 aufgerufen
fib wurde mit n = 1 aufgerufen
fib wurde mit n = 2 aufgerufen
fib wurde mit n = 1 aufgerufen
fib wurde mit n = 0 aufgerufen

Da wird fib() immer wieder mit den selben Parametern aufgerufen und neu berechnet.

Fibonacci mit besserem Algorithmus

#!/usr/bin/env python
# -*- coding: utf-8 -*-

cache = {}

def fib(n):
    "..."
    if (n in cache): return cache[n]
    
    if n == 0: return 0
    if n == 1: return 1
    result = fib(n - 1) + fib(n - 2)
    
    cache[n] = result
    return result

print fib(30)

Das Zahl wird jetzt in weniger als 0.001 Sekunden berechnet :D

ENDE