在Python生成器中访问局部变量
你怎么能从外部访问一个在Python生成器内部定义的局部变量呢?
我有一个情况,我的生成器在处理一些局部状态,而在单元测试中,我想检查这个状态,以确保它包含正确的值。
我不能把状态存储到实例变量里(比如 self.state = blah),因为我可能会从同一个类实例创建多个生成器,这样的话,生成器之间可能会互相覆盖状态。我也不能在 yield 表达式中返回状态,因为状态的名称可能会变化,或者因为每个生成器实例的不同而有所不同。
例如,我想做类似这样的事情(不过这段代码是不能工作的)
from random import random
class MyIter(object):
def __iter__(self):
context = {}
for i in xrange(10):
context[random()] = random()
yield i
obj = MyIter()
i1 = iter(obj)
i2 = iter(obj)
while 1:
try:
i1.next()
i2.next()
print i1.context
print i2.context
except StopIteration:
break
有没有办法通过检查Python的执行栈来访问局部变量呢?
3 个回答
0
如果你真的想这么做,可以把迭代器类和容器类分开:
from random import random
class MyContainer(object):
def __iter__(self):
return MyIter(self)
class MyIter(object):
def __init__(self, container):
self.container = container
self.context = {}
self.it = iter(xrange(10))
def next(self):
self.context[random()] = random()
return next(self.it)
def __iter__(self):
return self
obj = MyContainer()
# ...
不过我觉得这样做并不是特别有用...
1
你应该把生成器当作一个黑箱子来看待。单元测试不应该关注它内部的状态,因为那只是实现的细节;它们只需要关注预期的行为就可以了。
4
抱歉我自己回答自己的问题,不过在深入研究生成器接口后,我找到了访问生成器本地变量的确切路径:
from random import random
class MyIter(object):
def __iter__(self):
context = {}
for i in xrange(10):
context[random()] = random()
yield i
obj = MyIter()
i1 = iter(obj)
i2 = iter(obj)
while 1:
try:
i1.next()
i2.next()
print i1.gi_frame.f_locals['context']
print i2.gi_frame.f_locals['context']
except StopIteration:
break