有什么办法可以在运行时影响当地人吗?

发布于 2024-08-06 23:26:26 字数 542 浏览 9 评论 0原文

我实际上想创建一个新的本地。我知道这听起来很可疑,但我认为我有一个很好的用例。本质上我的问题是,当我尝试打印鸡蛋时,此代码会抛出“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 技术交流群。

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

发布评论

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

评论(3

荭秂 2024-08-13 23:26:26

我对你的用例非常好奇。你到底为什么要尝试将一个新的局部变量插入调用者的框架中,而不是简单地执行这样的操作:

def f():
    return 123

def g():
    eggs = f()
    print(eggs)

毕竟,你可以返回一个包含任意多个值的元组:

def f():
    return 123, 456, 789

def g():
    eggs, ham, bacon = f()
    print(eggs, ham, bacon)

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:

def f():
    return 123

def g():
    eggs = f()
    print(eggs)

After all, you can return a tuple with as many values as you like:

def f():
    return 123, 456, 789

def g():
    eggs, ham, bacon = f()
    print(eggs, ham, bacon)
〆凄凉。 2024-08-13 23:26:26

正如 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.

晚雾 2024-08-13 23:26:26

在 Python 2.* 中,您可以通过破坏局部变量的正常优化来使此类代码正常工作:

>>> def g():
...   exec 'pass'
...   f()
...   print(eggs)

exec 语句的存在会导致 Python 2 以完全不同的方式编译 g。非优化方式,因此本地变量位于字典中,而不是像通常那样位于数组中。 (性能损失可能相当大)。

这种“去优化”在 Python 3 中不存在,其中 exec 不再是一条语句(甚至不是关键字,只是一个函数)——即使在后面加上括号也无济于事。 ..:

>>> def x():
...   exec('a=23')
...   print(a)
... 
>>> x()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in x
NameError: global name 'a' is not defined
>>> 

即,甚至 exec 现在也不能“创建在 def 时不知道的局部变量”(即,当编译器完成传递函数体时)转换为字节码)。

你最好的选择就是放弃。第二个最好的方法是让您的 f 函数将新名称注入调用者的 globals 中——毕竟,那些仍然是一个字典。

In Python 2.*, you can get such code to work by defeating the normal optimization of locals:

>>> def g():
...   exec 'pass'
...   f()
...   print(eggs)

The presence of an exec statement causes Python 2 to compile g 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...:

>>> def x():
...   exec('a=23')
...   print(a)
... 
>>> x()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in x
NameError: global name 'a' is not defined
>>> 

i.e., not even exec can now "create locals" that were not know at def-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's globals -- those are still a dict, after all.

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