Florian Lindner wrote:
Am Montag 04 Juli 2011, 13:57:09 schrieb Peter Otten:
Florian Lindner wrote:
Am Samstag 02 Juli 2011, 17:35:00 schrieb Stefan Schwarzer:
Hallo Florian,
On 2011-07-02 12:25, Florian Lindner wrote:
Am Dienstag 28 Juni 2011, 21:10:46 schrieb Hans-Peter Jansen:
On Tuesday 28 June 2011, 16:25:04 Florian Lindner wrote: async = Async(threading.Thread)
In [7]: @async
...: def add(b): ...: return b+2
...: In [8]: add(4) Out[8]: <Thread(add-1, stopped 139819357185792)>
Das klappt soweit alles ganz gut. Wenn ich allerdings die callback funktionen benutzen will, bekomme ich es nicht hin:
In [9]: def os(result): ...: print "Success", result
ich würde eher davon abraten, eine Funktion so zu nennen wie ein häufig benutztes Modul aus der Standard-Bibliothek. Das kann leicht zu Verwirrung führen.
Klaro, das war so nur in die Shell gehackt.
TypeError: __call__() takes at least 2 arguments (2 given)
Die Methode akzeptiert mindestens zwei Parameter, die du auch angegeben hast, aber du bekommst einen TypeError dazu? Hast du die Fehlermeldung richtig übernommen?
Ein komplettes Skript schaut jetzt so aus:
from common import Async import threading
async = Async(threading.Thread)
def o_s(result): print "Success: ", result
@async(on_success=o_s)
def add(x): return x+2
res = add(2) print res
und wenn es ausgeführt wird:
florian@horus ~/SA/src (git)-[master] % python2 test.py
Traceback (most recent call last): File "test.py", line 9, in <module>
@async(on_success=o_s)
TypeError: __call__() takes at least 2 arguments (2 given)
Version von python ist 2.7.2.
Faszinierende Fehlermeldung; Python 2.6 ist dagegen richtig langweilig:
$ python async.py
Traceback (most recent call last): File "async.py", line 68, in <module> @async(on_success=on_success) TypeError: __call__() takes at least 2 non-keyword arguments (1 given)
Wenn ich den Dekorator ohne Argumente benutze funktioniert es, aber halt kein Callback.
Probier es mal zu Fuß:
def add(x): return x + 2 add = async(add, on_success=o_s)
Das funktioniert:
florian@horus ~/SA/src (git)-[master] % python2 test.py Success: <Thread(add-1, started 140544079726336)> 4
bei Python 2.6 ebenfalls? Hast Du eine Idee woran es liegen könnte?
Ja klar. @async(on_success=callback) def add(x): return x + 2 entspricht def add(x): return x + 2 add = async(on_success=callback)(add) Dafür ist Async.__call__() nicht ausgelegt; es erwartet immer die zu dekorierende Funktion als (abgesehen von self) erstes Argument. Hier eine modifizierte Version, bei der die __call__-Methode eine Fallunterscheidung vornimmt: import itertools from decorator import decorator from functools import partial def on_success(result): # default implementation "Called on the result of the function" print "Default", result def on_failure(exc_info): # default implementation "Called if the function fails" pass def on_closing(): # default implementation "Called at the end, both in case of success and failure" pass class Async(object): """ A decorator converting blocking functions into asynchronous functions, by using threads or processes. Examples: async_with_threads = Async(threading.Thread) async_with_processes = Async(multiprocessing.Process) """ def __init__(self, threadfactory): self.threadfactory = threadfactory def __call__(self, func=None, on_success=on_success, on_failure=on_failure, on_closing=on_closing): if func is None: return partial(self, on_success=on_success, on_failure=on_failure, on_closing=on_closing) # every decorated function has its own independent thread counter func.counter = itertools.count(1) func.on_success = on_success func.on_failure = on_failure func.on_closing = on_closing return decorator(self.call, func) def call(self, func, *args, **kw): def func_wrapper(): try: result = func(*args, **kw) except: func.on_failure(sys.exc_info()) else: return func.on_success(result) finally: func.on_closing() name = '%s-%s' % (func.__name__, func.counter.next()) thread = self.threadfactory(None, func_wrapper, name) thread.start() return thread if __name__ == "__main__": import threading async = Async(threading.Thread) @async def add_one(b): return b+1 add_one(4) def on_success(result): print "Success", result @async(on_success=on_success) def add_two(b): return b+2 add_two(42) Ich habe versucht, so wenig wie möglich an der Klasse zu ändern.