访问Python生成器中的局部变量

时间:2011-01-19 14:38:44

标签: python scripting iterator generator

如何从生成器外部访问Python生成器中定义的局部变量?

我有一个案例,我的生成器操纵一个本地状态,而对于单元测试,我想检查这个状态,以确保它包含正确的值。

我无法将状态存储到实例变量(例如self.state = blah),因为我可能正在从同一个类实例创建多个生成器,这意味着生成器可能会覆盖彼此的状态。我也无法在yield表达式中返回状态,因为状态名称可能因个别生成器实例而改变或变化。

e.g。我想做这样的事情(尽管这段代码不起作用)

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 :(得分: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

答案 1 :(得分:0)

您应该将发电机视为黑匣子。单元测试不应该关心它的内部状态,因为这只是一个实现细节;他们应该只关心指定的行为。

答案 2 :(得分: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()
# ...

虽然我不认为这非常有用......