[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