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: * `Dokumentation des inspect-Moduls `_ 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: * `Dokumentation des decorator-Moduls `_ * `decorator-2.2.0.zip `_ (die Version, die im Buch benutzt wurde) * `decorator-2.3.1.zip `_ (eine aktuellere Version -- last checked 2008/07/31) 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: * `Dokumentation des threading-Moduls Screenshot `_ URLs: * `Dokumentation des threading-Moduls `_ Zusammenfassung ===============