[Python-de] subprocess mit callback
Florian Lindner
mailinglists at xgm.de
Sa Jul 9 12:56:15 CEST 2011
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
Mehr Informationen über die Mailingliste python-de