Does a generator decorator exist?
I just got through tracking down a random bug while using Twisted:
Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/twisted/spread/pb.py", line 826, in proto_message
self._recvMessage(self.localObjectForID, requestID, objectID, message, answerRequired, netArgs, netKw)
File "/usr/lib/python2.7/dist-packages/twisted/spread/pb.py", line 840, in _recvMessage
netResult = object.remoteMessageReceived(self, message, netArgs, netKw)
File "/usr/lib/python2.7/dist-packages/twisted/spread/flavors.py", line 114, in remoteMessageReceived
state = method(*args, **kw)
File "/usr/lib/python2.7/dist-packages/twisted/internet/defer.py", line 1141, in unwindGenerator
return _inlineCallbacks(None, f(*args, **kwargs), Deferred())
--- <exception caught here> ---
File "/usr/lib/python2.7/dist-packages/twisted/internet/defer.py", line 1020, in _inlineCallbacks
result = g.send(result)
exceptions.AttributeError: 'NoneType' object has no attribute 'send'
This was caused by:
@defer.inlineCallbacks
def myfunc():
# Function implementation with no yield statement.
And when the myfunc
was called, I would get the previous traceback printed but with everything within the function working properly. This is because it returned None
instead a generator when called, which defer.inlineCallbacks
expects to be returned. Is ther开发者_JAVA百科e way to declare a function a generator without placing a yield statement within the function body? Such as a generator decorator?
As others have noted, this likely makes no sense. But for completeness and to answer the question:
No, you have to use a yield
to make it a generator, except of course if you create a decorator that's a generator (by including the yield
keyword) itself but doesn't actually yield anything and just calls the decorated function. Such a yield
can be unreachable and pointless (if False: yield
), but it has to be there. As this isn't a common need, there is nothing like the latter pre-built, at least nothing I'm aware of. The by far simplest way is to just add this to your function, writing your own decorator isn't worth it for a few cases and should you need it frequently, there's probably something wrong without your design and you should fix that instead.
If you really need it, make one up.
#like this
def generator(callable):
def asgenerator(*args, **kwargs):
while True:
yield callable(*args, **kwargs)
return asgenerator
Although, as noted by others, this is probably hiding a design problem.
Looks like you've bumped into Ticket 2501. This is already fixed in trunk, and the error you encounter will be much clearer in the future.
精彩评论