有什么办法可以在运行时影响当地人吗?
我实际上想创建一个新的本地。我知道这听起来很可疑,但我认为我有一个很好的用例。本质上我的问题是,当我尝试打印鸡蛋时,此代码会抛出“NameError:全局名称'eggs'未定义”:
def f():
import inspect
frame_who_called = inspect.stack()[1][0]
frame_who_called.f_locals['eggs'] = 123
def g():
f()
print(eggs)
g()
我发现了这个旧东西: http://mail.python.org/pipermail/python- dev/2005-January/051018.html
这意味着我可以使用 ctypes 并调用一些秘密函数来做到这一点,尽管他们只讨论了更新值。但也许有更简单的方法?
I actually want to create a new local. I know it sounds dubious, but I think I have a nice use case for this. Essentially my problem is that this code throws "NameError: global name 'eggs' is not defined" when I try to print eggs:
def f():
import inspect
frame_who_called = inspect.stack()[1][0]
frame_who_called.f_locals['eggs'] = 123
def g():
f()
print(eggs)
g()
I found this old thing:
http://mail.python.org/pipermail/python-dev/2005-January/051018.html
Which would mean I might be able to do it using ctypes and calling some secret function, though they only talked about updating a value. But maybe there's an easier way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我对你的用例非常好奇。你到底为什么要尝试将一个新的局部变量插入调用者的框架中,而不是简单地执行这样的操作:
毕竟,你可以返回一个包含任意多个值的元组:
I am highly curious as to your use case. Why on Earth are you trying to poke a new local into the caller's frame, rather than simply doing something like this:
After all, you can return a tuple with as many values as you like:
正如 Greg Hewgill 在对该问题的评论中提到的,我回答了另一个问题在 Python 3 中修改
locals
,我将在这里进行一些回顾。关于这个问题,Python 3 bug 列表上有一篇文章——它在 Python 中的记录有点少3 份手册。 Python 3 使用数组作为局部变量,而不是像 Python 2 那样使用字典——优点是局部变量的查找时间更快(Lua 也这样做)。基本上,该数组是在“字节码编译时”定义的,并且不能在运行时修改。
具体请参阅 Georg Brandl 在错误列表上的帖子中的最后一段,了解有关为什么不能这样做的更详细信息(以及可能永远不会)在 Python 3 中工作。
As Greg Hewgill mentioned in a comment on the question, I answered another question about modifying
locals
in Python 3, and I'll give a bit of a recap here.There is a post on the Python 3 bug list about this issue -- it's somewhat poorly documented in the Python 3 manuals. Python 3 uses an array for locals instead of a dictionary like in Python 2 -- the advantage is a faster lookup time for local variables (Lua does this too). Basically, the array is defined at "bytecode-compile-time" and cannot be modified at runtime.
See specifically the last paragraph in Georg Brandl's post on the bug list for finer details about why this cannot (and probably never will) work in Python 3.
在 Python 2.* 中,您可以通过破坏局部变量的正常优化来使此类代码正常工作:
exec
语句的存在会导致 Python 2 以完全不同的方式编译g
。非优化方式,因此本地变量位于字典中,而不是像通常那样位于数组中。 (性能损失可能相当大)。这种“去优化”在 Python 3 中不存在,其中
exec
不再是一条语句(甚至不是关键字,只是一个函数)——即使在后面加上括号也无济于事。 ..:即,甚至
exec
现在也不能“创建在def
时不知道的局部变量”(即,当编译器完成传递函数体时)转换为字节码)。你最好的选择就是放弃。第二个最好的方法是让您的
f
函数将新名称注入调用者的globals
中——毕竟,那些仍然是一个字典。In Python 2.*, you can get such code to work by defeating the normal optimization of locals:
The presence of an
exec
statement causes Python 2 to compileg
in a totally non-optimized fashion, so locals are in a dict instead of in an array as they normally would be. (The performance hit can be considerable).This "de-optimization" does not exist in Python 3, where
exec
is not a statement any more (not even a keyword, just a function) -- even putting parentheses after it doesn't help...:i.e., not even
exec
can now "create locals" that were not know atdef
-time (i.e., when the compiler did its pass to turn the function body into bytecode).Your best bet would be to give up. Second best would be to have your
f
function inject new names into the caller'sglobals
-- those are still a dict, after all.