Dies ist die Support Website des Buches:

Das Python Praxisbuch
Der große Profi-Leitfaden für Programmierer
Farid Hajji
Addison Wesley / Pearson Education
ISBN 978-3-8273-2543-3 (Sep 2008), 1298 Seiten.

8. Funktionen

Funktionen aufrufen

Die Funktion foo:

def foo(p1, p2):
    "Transmogrify p1 and p2 into a string."
    return p1[::-1] + p2

Die Funktion foobar:

def foobar(p1, p2="world"):
    "Transmogrify p1 and p2 into a string."
    return p1[::-1] + p2

Funktionsparameter

Die Funktion foo:

def foo(p1, p2=42, *p, **kw):
    "Print positional parameters, *p and **kw forms"
    print "p1   =", p1
    print "p2   =", p2
    print "*p   =", p
    print "**kw =", kw

Die Funktion summer:

def summer(*p):
    "Sum all numbers"
    result = 0
    for num in p:
        result = result + num
    return result

Die Funktion foobar:

def foobar(p1, store={}):
    "Function with meta data"

    if isinstance(store, dict):
        store['counter'] = store.get('counter', 0) + 1
        print "foobar called", store['counter'], "time(s)"
    else:
        print "store(shadowed) =", store

    # Do something with p1
    print "p1 =", p1

Die Funktion foobar2:

def foobar2(p1, store={}):
    "Function with meta data"

    if isinstance(store, dict):
        the_counter = store.get('counter', 0)
        if isinstance(the_counter, int):
            store['counter'] = the_counter + 1
            print "foobar2 called", store['counter'], "time(s)"
        else:
            # store['counter'] wasn't a counter!
            print "store =", store
    else:
        print "store(shadowed) =", store

    # Do something with p1:
    print "p1 =", p1

Rückgabewerte

Die Funktionen foo1 und foo2:

def foo1():
    "Return multiple values in a list"
    return ['john doe', '555-2323', 'jdoe@example.com']

def foo2():
    "Return multiple values in a dictionary"
    return {'name': 'john doe', 'phone': '555-2323',
            'email': 'jdoe@example.com'}

Scope

Die Funktion set_a:

def set_a(value):
    "Set a to value"
    a = value
    print "New value:", a

Die Funktion set_b:

def set_b(value):
    "Set global b to value"
    global b
    b = value
    print "New value:", b

Lokale und globale Namensräume verstehen

Die Funktion show_namespaces:

import pprint

def show_namespaces():
    "Display local and global namespaces"
    foo = 'a local variable'
    bar = 99999
    print "locals() =="
    pprint.pprint(locals())
    print "globals() =="
    pprint.pprint(globals())

Die Funktion factorial:

def factorial(n):
    "Returns n!"
    result = n
    if result > 1:
        result = result * factorial(n-1)
    print "locals() of factorial(%d) ==" % n, locals()
    return result

Ein Blick unter die Haube

Die Funktion f:

def f(p1, p2='hi', *alist, **adict):
    "A function that prints its arguments"
    print "p1:", p1
    print "p2:", p2
    print "*alist:", alist
    print "**adict:", adict
    return [ p1, p2 ]

Disassembliert sieht es so aus:

>>> inspect.dis.disassemble(fc)
  3           0 LOAD_CONST               1 ('p1:')
              3 PRINT_ITEM
              4 LOAD_FAST                0 (p1)
              7 PRINT_ITEM
              8 PRINT_NEWLINE

  4           9 LOAD_CONST               2 ('p2:')
             12 PRINT_ITEM
             13 LOAD_FAST                1 (p2)
             16 PRINT_ITEM
             17 PRINT_NEWLINE

  5          18 LOAD_CONST               3 ('*alist:')
             21 PRINT_ITEM
             22 LOAD_FAST                2 (alist)
             25 PRINT_ITEM
             26 PRINT_NEWLINE

  6          27 LOAD_CONST               4 ('**adict:')
             30 PRINT_ITEM
             31 LOAD_FAST                3 (adict)
             34 PRINT_ITEM
             35 PRINT_NEWLINE

  7          36 LOAD_FAST                0 (p1)
             39 LOAD_FAST                1 (p2)
             42 BUILD_LIST               2
             45 RETURN_VALUE

Die Funktion g:

def g(a, b):
    "Add two numbers, and return the result"
    res = a + b
    return res

sieht disassembliert so aus:

>>> inspect.dis.disassemble(g.func_code)
  3           0 LOAD_FAST                0 (a)
              3 LOAD_FAST                1 (b)
              6 BINARY_ADD
              7 STORE_FAST               2 (res)

  4          10 LOAD_FAST                2 (res)
             13 RETURN_VALUE

Screenshots:

Factory-Funktionen und -Closures

Die Funktion create_prompter:

def create_prompter(prompt):
    "A factory that creates prompting functions"
    def prompter():
        "Ask the user a question and return reply as string"
        return raw_input(prompt + " ")
    return prompter

Dekoratoren

Dekoratoren manuell erstellen

Die Funktion foo:

def foo():
    "A very simple function"
    print "I am foo()"

Die Funktion tracefoo:

def tracefoo():
    "Trace each call to foo"
    print "TRACE: foo"
    return foo()

Die Factory-Funktion tracer_function:

def tracer_function(f):
    "Create a tracer for function f"
    def tracer():
        "A tracer for f"
        print "TRACE:", f.func_name
        return f()
    return tracer

Die Funktion bar mit Dekorator tracer_function:

@tracer_function
def bar():
    "Another very simple function"
    print "I am bar()"

Die Funktion doubler:

def doubler(num):
     "Returns the double of a number num"
     return num + num

Die Funktion tracer_function_1arg:

def tracer_function_1arg(f):
    "Create a tracer for function f, where f takes one argument"
    def tracer(thearg):
        "A tracer for f"
        print "TRACE:", f.func_name
        return f(thearg)
    return tracer

Die Funktion tracer_function_general:

def tracer_function_general(f):
    "Create a tracer for function f, f takes *p and **kw forms"
    def tracer(*p, **kw):
        "A tracer for f"
        print "TRACE:", f.func_name
        return f(*p, **kw)
    return tracer

Die Funktion tracer_function_with_name:

def tracer_function_with_name(f):
    "Create a tracer function for f; preserve function name"
    def tracer(*p, **kw):
        print "TRACE:", f.func_name
        return f(*p, **kw)
    tracer.func_name = f.func_name
    tracer.func_doc  = f.func_doc
    return tracer

Die Funktion tracer_function_with_name_and_dict:

def tracer_function_with_name_and_dict(f):
    "Create a tracer function for f; preserve function name and attrs."
    def tracer(*p, **kw):
        print "TRACE:", f.func_name
        return f(*p, **kw)
    tracer.func_name = f.func_name
    tracer.func_doc  = f.func_doc
    tracer.__dict__.update(f.__dict__)
    return tracer

Die Funktion tracer_function_with_update_wrapper:

def tracer_function_with_update_wrapper(f):
    "Create a tracer function for f; preserve attributes"
    def tracer(*p, **kw):
        print "TRACE:", f.func_name
        return f(*p, **kw)
    functools.update_wrapper(tracer, f)
    return tracer

Das decorator-Modul

URLs:

traced

Der traced-Dekorator:

from decorator import decorator

@decorator
def traced(f, *p, **kw):
    "A tracer decorator"
    print "TRACE:", f.func_name
    return f(*p, **kw)

Eine traced Funktion doubler:

@traced
def doubler(num):
    "Returns the double of a number num"
    return num + num

profiled

Der profiled-Dekorator:

from decorator import decorator
from inspect import getargspec

@decorator
def profiled(f, *p, **kw):
    "A call counter decorator"
    if hasattr(f, "count"):
        f.count = f.count + 1
    else:
        f.count = 1
    print "PROFILER: %s called %d times(s)" % (f.func_name, f.count)
    return f(*p, **kw)

Die Funktion doubler jetzt profiled:

@profiled
def doubler(num):
    "Returns the double of number num"
    return num + num

memoized

Der memoized-Dekorator:

from decorator import decorator
from inspect import getargspec

@decorator
def memoized(f, *p):
    "A memoizing decorator"
    if not hasattr(f, "store"):
        f.store = {}
    if p in f.store:
        return f.store[p]
    else:
        result = f(*p)
        f.store[p] = result
        return result

Die memoized-Version von doubler:

@memoized
def doubler(num):
    "Doubles number num"
    return num + num

Die Funktion timeme:

import time

def timeme(f, *p):
    "Compute and return f(p), and print time in seconds"
    start_time = time.time()
    result = f(*p)
    end_time = time.time()
    print "RUN TIME: %s took %.2f seconds" % (f.func_name,
                                              end_time - start_time)
    return result

Die Funktion fib1:

def fib1(n):
    "Computer fibonacci(n) recursively"
    if n == 1 or n == 2:
        return 1
    else:
        return fib1(n-1) + fib1(n-2)

Die Funktion fib2:

@memoized
def fib2(n):
    "Computer fibonacci(n) recursively"
    if n == 1 or n == 2:
        return 1
    else:
        return fib2(n-1) + fib2(n-2)

Die Funktion fast_pow:

@memoized
def fast_pow(x, y):
    "Compute pow(x, y) and cache the results"
    return pow(x, y)

synchronized

Der synchronized-Dekorator:

from decorator import decorator
import threading

@decorator
def synchronized(f, *p, **kw):
    "Make a function synchronized in the Java sense"
    lock = threading.Lock()
    lock.acquire()
    try:
        result = f(*p, **kw)
    finally:
        lock.release()
    return result

Die synchronisierte Funktion write:

import time

@synchronized
def write(data):
    "Writing to a single-access resouce"
    time.sleep(1)
    datalist.append(data)

Der delayed-Dekorator:

from decorator import decorator
import threading

def delayed(nsec):
    "A factory of decorators which launch a function after a delay"
    def delayed_call(f, *p, **kw):
        "Call f(*p, **kw) in a thread after a delay"
        thread = threading.Timer(nsec, f, p, kw)
        thread.start()
        return thread
    return decorator(delayed_call)

Ein verzögertes Schreiben:

@delayed(2)
def write_delayed(data):
    write(data)

Der threaded-Dekorator ist ein Sonderfall des delayed-Dekorators:

>>> threaded = delayed(0)

Die Funktion long_computation:

@threaded
def long_computation(maxval):
    "Perform some long running computation"
    i = 0
    while i < maxval:
        i = i + 1
    print "Finished computation. Result: %d" % (i,)
    return i

Screenshots:

URLs:

Zusammenfassung