开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜