如何在python中修改本地命名空间

2022-01-14 00:00:00 python namespaces local

问题描述

如何在 python 中修改函数的本地命名空间?我知道 locals() 在函数内部调用时会返回函数的本地命名空间,但我想做这样的事情(我有一个理由要在 f 无法访问 g 的情况下执行此操作,但给出更快一个简单的、愚蠢的例子来说明问题):

How can I modify the local namespace of a function in python? I know that locals() returns the local namespace of the function when called inside it, but I want to do something like this (I have a reason why I want to do this where g is not accessible to f, but it's quicker to give a trivial, stupid example to illustrate the problem):

def g():
   pass

def f():
    g()

f.add_to_locals({'g':g})


解决方案

你有几个选择.首先,请注意,您的示例中的 g 实际上并不是函数的局部变量(即未在其中分配),它是全局变量(即尚未分配给局部变量).这意味着它将在定义函数的模块中查找它.这是幸运的,因为没有办法在外部更改本地变量(除了修补字节码),因为它们是在函数运行时分配的,而不是之前.

You've a couple of options. First, note that g in your example isn't actually a local to the function (ie. not assigned within it), it's a global (ie hasn't been assigned to a local variable). This means that it will be looked up in the module the function is defined in. This is fortunate, as there's no way of altering locals externally (short of patching the bytecode), as they get assigned when the function runs, not before.

一种选择就是将你的函数注入到函数模块的命名空间中.这将起作用,但会影响该模块中访问变量的每个函数,而不仅仅是一个函数.

One option is simply to inject your function into the function's module's namespace. This will work, but will affect every function in that module that accesses the variable, rather than just the one function.

要只影响一个函数,您需要将 func_globals 指向其他地方.不幸的是,这是一个只读属性,但您可以通过使用相同的主体但不同的全局命名空间重新创建函数来做您想做的事情:

To affect just the one function, you need to instead point that func_globals somewhere else. Unfortunately, this is a read-only property, but you can do what you want by recreating the function with the same body, but a different global namespace:

import new
f = new.function(f.func_code, {'g': my_g_function}, f.func_name, f.func_defaults, f.func_closure)

f 现在将是相同的,除了它将在提供的 dict 中查找全局变量.请注意,这会重新绑定整个全局名称空间 - 如果那里有 f 确实 查找的变量,请确保您也提供它们.不过,这也相当 hacky,并且可能不适用于 cpython 以外的 python 版本.

f will now be indentical, except that it will look for globals in the provided dict. Note that this rebinds the whole global namespace - if there are variables there that f does look up, make sure you provide them too. This is also fairly hacky though, and may not work on versions of python other than cpython.

相关文章