2014-02-16 13 views
10

Gibt es eine Möglichkeit, einen Verweis auf das zurückgegebene Generatorobjekt innerhalb der Definition des Generators zu erhalten? Dies wäre vergleichbar mit dem self-Argument, das an die Methode innerhalb der __next__-Methode eines Iterators übergeben wird. Nach dem Durchsuchen der Python-Dokumentation habe ich nichts Ähnliches gefunden.Gibt es etwas Ähnliches wie "self" in einem Python-Generator?

Diese Frage entstand, während ich erforschte, wie viel der Ideen des folgenden Papiers ich in Python mit Generatoren als Koroutinen implementieren kann. Papier: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.19.79

Das nächste, was ich tun konnte, war das Folgende, mit einem Dekorateur, der auf David Beazley coroutine Dekorateur baut, aber es fühlt sich an wie ein bisschen wie ein Hack.

from functools import wraps 


def coroutine(func): 
    @wraps(func) 
    def decorated(*args, **kwargs): 
     f = func(*args, **kwargs) 
     next(f) 
     f.send(f) 
     return f 
    return decorated 


@coroutine 
def A(): 
    self = yield 
    # do stuff... 

EDIT: Die folgende Klasse, basierend auf der Antwort unten, kann als Dekorateur verwendet werden, den Generator zu haben, einen Verweis auf self als ersten Paramter erhalten. Es hat den zusätzlichen Vorteil, dass jeder damit ausgestattete Generator den Typ coroutine hat.

class coroutine(object): 
    """Decorator class for coroutines with a self parameter.""" 
    def __new__(cls, func): 
     @wraps(func) 
     def decorated(*args, **kwargs): 
      o = object.__new__(cls) 
      o.__init__(func, args, kwargs) 
      return o 
     return decorated 

    def __init__(self, generator, args, kw): 
     self.generator = generator(self, *args, **kw) 
     next(self.generator) 

    def __iter__(self): 
     return self 

    def __next__(self): 
     return next(self.generator) 

    next = __next__ 

    def send(self, value): 
     return self.generator.send(value) 


# Usage: 

@coroutine 
def A(self): 
    while True: 
     message = yield 
     print self is message 


a = A() 
b = A() 
a.send(a) # outputs True 
a.send(b) # outputs False 
+0

Ich habe kurz über ein Drittel der Zeitung überflogen, und ich habe nichts gesehen, wofür eine Coroutine einen Verweis auf sich selbst haben sollte. Es sah so aus, als ob eine Coroutine die Coroutine bei jedem gegebenen Index auslösen sollte. Ist das genau, oder sollte ich zurückgehen und tatsächlich die Zeitung lesen anstatt zu skimmen? – user2357112

+1

Wenn Sie möchten, dass eine Coroutine einen Verweis auf sich selbst hat, wofür würden Sie sie verwenden? Würde sich die Coroutine selbst als Callback zu einem anderen Teil des Codes ausgeben? – user2357112

+1

können Sie einen gebrauchten Fall setzen, eigentlich bin ich nicht klar, was Sie versuchen zu tun. –

Antwort

3

Hier ist ein Vorschlag mit einem Proxy.

def selfDecorator(func): 
    def wrap(*args, **kw): 
     return SelfGenerator(func, args, kw) 
    return wrap 

class SelfGenerator(object): 
    """This class implements the generator interface""" 
    def __init__(self, generator, args, kw): 
     self.generator = generator(self, *args, **kw) 
    def __iter__(self): 
     return self 
    def __next__(self): 
     return next(self.generator) 
    next = __next__ 
    def send(self, value): 
     return self.generator.send(value) 

@selfDecorator 
def gen(self, x): # your generator function with self 
    for i in range(x): 
     yield self 


for x in gen(5): 
    print x # prints <__main__.SelfGenerator object at 0x02BB16D0> 

Da SelfGenerator ist ein Proxy auf den ursprünglichen Generator es die gleiche Schnittstelle und kann vollständig verwendet werden, wie die Pythons Generator besitzen.

erste Antwort

Sie nicht einen Generator an sich nennen kann:

>>> def generator(): 
    for value in g: 
     yield value 


>>> g = generator() 
>>> next(g) 

Traceback (most recent call last): 
    File "<pyshell#13>", line 1, in <module> 
    next(g) 
    File "<pyshell#11>", line 2, in generator 
    for value in g: 
ValueError: generator already executing 

Erraten: Das Selbst in dem Papier nicht den Generator selbst bedeuten, sondern ein Objekt, einige Zustand Halter, der vielleicht wird zwischen einigen Generatoren geteilt.

Genauer gesagt muss der gerichtete Graph der Nebenbedingungen zyklusfrei sein, wenn er als ungerichteter Graph betrachtet wird.

Das lässt mich denken, dass der Generator sich nicht auf seine "identische" Ausführung bezieht. Warum sollte es durch Iteration seinen eigenen Wert aus sich heraus bekommen? Es kann eine lokale Variable verwenden.

Coroutines stammen von Simula. Vielleicht um zu verstehen, was das Selbst ist, kannst du dir die Sprache anschauen.

+0

Haben Sie ein Zitat für "Coroutines stammen von Simula"? Ein kurzer Scan der relevanten Seiten auf Wikipedia ist eindeutig mehrdeutig; Es ist möglich, dass Simula nur ein früher Anwender war. (A _very_ early adopter.) –

+0

Nein, ich habe kein Zitat. Es wurde mein Wissen, wenn ich etwas über die Geschichte der Objektorientierung lese. Nach meinem Wissen ist es der erste Adopter. (= Herkunft) Vielleicht der erste erfolgreiche Adopter. Ich schrieb dies, weil ich nicht sicher bin, was Sahand mit "Selbst" meint. Ein laufender Generator, der auf sich selbst verweist, ergibt für mich keinen Sinn. – User

+0

Ich fragte nur, weil ich neugierig war, und weil ein schneller Scan von WP nicht klar war. (Ich bin nicht bei der Arbeit, deshalb kann ich die Literatur nicht so leicht direkt lesen.) Ich finde es faszinierend, dass Coros ein Merkmal sind, das lange Zeit in Ungnade gefallen ist und dennoch in den letzten Jahren eine Renaissance erlebt hat . –

Verwandte Themen