是否存在生成器装饰器?
我刚刚在使用Twisted的时候,追踪到一个随机出现的bug:
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'
这个问题是由以下原因引起的:
@defer.inlineCallbacks
def myfunc():
# Function implementation with no yield statement.
当调用myfunc
的时候,我会看到之前的错误信息被打印出来,但函数内部的所有东西都正常工作。这是因为它返回了None
,而不是一个生成器,而defer.inlineCallbacks
是期待返回一个生成器的。有没有办法在函数体内不放置yield语句的情况下,把一个函数声明为生成器?比如说使用一个生成器装饰器?
3 个回答
1
看起来你遇到了问题单 2501。这个问题已经在最新版本中修复了,以后你遇到的错误信息会更清晰明了。
1
如果你真的需要这个,那就自己想一个吧。
#like this
def generator(callable):
def asgenerator(*args, **kwargs):
while True:
yield callable(*args, **kwargs)
return asgenerator
不过,正如其他人提到的,这可能是在掩盖一个设计上的问题。
6
正如其他人提到的,这可能听起来有点奇怪。不过为了完整性和回答这个问题:
不,你必须使用 yield
来让它变成一个生成器,当然,如果你创建一个本身就是生成器的装饰器(通过包含 yield
关键字),但实际上并不返回任何东西,只是调用被装饰的函数,那也是可以的。这样的 yield
可能是不可达的,也没有实际意义(比如 if False: yield
),但它必须存在。因为这种需求并不常见,所以没有现成的解决方案,至少我不知道有什么。最简单的方法就是直接在你的函数中添加这个,自己写一个装饰器对于少数情况来说并不划算,如果你经常需要这样做,可能你的设计有问题,应该先去修正它。