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

发布于 2024-10-12 23:19:20 字数 687 浏览 8 评论 0原文

如何从生成器外部访问 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的执行堆栈来访问局部变量?

How would you access a local variable defined inside a Python generator from outside the generator?

I have a case where my generator manipulates a local state, and for unittests I want to inspect this state to ensure it contains the correct values.

I can't store the state to an instance variable (e.g. self.state = blah), because I might be creating multiple generators from the same class instance, meaning the generators might overwrite each other's state. I also can't return the state in the yield expression, because the state name may change or vary because individual generator instances.

e.g. I want to do something like this (albeit this code doesn't work)

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

Is there anyway to access local variables by inspecting Python's execution stack?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

心如狂蝶 2024-10-19 23:19:20

很抱歉回答我自己的问题,但是在深入研究生成器接口后,我找到了访问生成器局部变量所需的确切路径:

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

Sorry to answer my own question, but after digging into the generator interface, I found the exact path I need to access the generator's local variables:

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
ゃ人海孤独症 2024-10-19 23:19:20

您应该将生成器视为黑匣子。单元测试不应该关心其内部状态,因为那只是一个实现细节;他们应该只关心指定的行为。

You should be treating the generator as a black box. Unit tests shouldn't care about its internal state, because that's just an implementation detail; they should only care about the specified behavior.

扭转时空 2024-10-19 23:19:20

如果你真的想这样做,请将迭代器类与容器类分开:

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()
# ...

但我认为这不是很有用......

If you really want to do this, separate the iterator class from the container class:

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()
# ...

I don't consider this very useful though...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文