
Am Freitag 08 Juli 2011, 18:10:03 schrieb Peter Otten:
Florian Lindner wrote:
Allerdings hören mein Problemchen mit dem Decorator da nicht auf. ;-) Als
ich ihn in meinen eigentlichen Code eingebaut habe: @async(on_sucess = self._cb_run_success)
def run(self): pass
das Problem ist nun, dass self für den Decorator gar nicht verfügbar ist.
Mir fallen da erstmal zwei "Lösungen" ein (in Anführungszeichen, da beide unerprobt)
1) den Callback _cb_run_success zur classmethod machen, damit braucht er kein self mehr. Allerdings greife ich im in der Methode schon auf self zu, müsste meinen Code also irgendwie umbauen. Damit könnte ich die on_success Methode auch gleich komplett außerhalb der Klase stellen.
2) In __init__ der Klasse den Dekorator partial instanziieren (<- richtiger Begriff?)
def __init__(self): self.my_async = functools.partial(async(on_success = self.o_s))
Leider - wie ich eben gerade merke - ist damit das Problem nur verschoben. @self.my_async funktioniert leider ebensowenig.
Ich habe dazu eine Diskussion gefunden http://stackoverflow.com/questions/3631768/is-it-bad-practice-to-use-sel f-
in-
decorators
Man kann wohl self im Code des Decorators bekommen, indem man Element [0] der positional Arguments ausliest *args. Das würde die allgemeine Verwendbarkeit des Dekorators wohl leider ziemlich einschränken.
Grüße und vielen Dank für alle weiteren Tipps!
Wenn ich dich richtig verstehe, läuft das auf etwas in der Art hinaus:
Ich habe es jetzt hinbekommen, dass es ohne Änderungen am aufrufenden Code funktioniert und gleichzeitig allgemein bleibt: 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: if "self" in getargspec(func.on_failure).args: func.on_failure(args[0], sys.exc_info()) else: func.on_failure(sys.exc_info()) else: if "self" in getargspec(func.on_success).args: return func.on_success(args[0], result) else: return func.on_success(result) finally: if "self" in getargspec(func.on_closing).args: func.on_closing(args[0]) else: func.on_closing() name = '%s-%s' % (func.__name__, func.counter.next()) thread = self.threadfactory(None, func_wrapper, name) thread.start() return thread In call() überprüfe ich die Signaturen der Callback-Funktionen und gebe ggfs. noch das entsprechende self, welches ich aus args[0] bekomme mit. getargspec stammt aus dem Modul inspect. Siehst Du da noch irgendwelche Probleme oder Verbesserungen? Grüße, Florian