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

时间:2022-01-29 21:25:59

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):

如何在python中修改函数的本地命名空间?我知道locals()在它内部调用时返回函数的本地命名空间,但是我想做这样的事情(我有理由为什么我要这样做,其中g不能被f访问,但它更快给出一个琐碎,愚蠢的例子来说明问题):

def g():
   pass

def f():
    g()

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

7 个解决方案

#1


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.

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

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.

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

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:

要仅影响一个函数,您需要将func_globals指向其他位置。不幸的是,这是一个只读属性,但您可以通过使用相同的主体重新创建函数来执行您想要的操作,但是可以使用不同的全局命名空间:

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

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.

f现在将是缩进的,除了它将在提供的字典中查找全局变量。请注意,这会重新绑定整个全局命名空间 - 如果f确实存在变量,请确保您也提供它们。这也是相当hacky,并且可能不适用于除pypy之外的python版本。

#2


Since the function isn't invoked, it has no "local" stack frame, yet. The most simple solution is to use a global context:

由于未调用该函数,因此它没有“本地”堆栈帧。最简单的解决方案是使用全局上下文:

handler = None
def f():
    handler()

def g(): pass

handler = g

Or you could set g on the function object:

或者你可以在函数对象上设置g:

f.g = g

But I'm not sure how you can get the function object from within the function itself. If it was a method, you would use self.

但我不确定如何从函数本身中获取函数对象。如果它是一种方法,你会使用自我。

#3


Why don't you just add an argument to f() and pass a reference to g()?

为什么不直接向f()添加一个参数并传递对g()的引用?

def g():
    pass

def f(func):
    func()

f(g)

#4


I think you could solve the problem tackling it from a completely different point.
Functions are object, with their dictionaries; therefore, you can add g to f, and use it:

我认为你可以从完全不同的角度解决问题。功能是对象,带有词典;因此,您可以将g添加到f,并使用它:

def g():
   print "g"

def f():
    f.g()

f.g = g

#5


I assume you want to do this, because the function f is defined not by you, but by some other module. So you want to change how f() works. In particular, you want to change what is called when g is called.

我假设您要这样做,因为函数f不是由您定义的,而是由其他模块定义的。所以你想改变f()的工作方式。特别是,您希望更改调用g时调用的内容。

So I'll suggest this:

所以我建议这个:

import thirdpartypackage

def mynewg():
   pass

thirdpartypackage.g = mynewg

This will change the global g for the module thirdpartypackage. So when thirdpartypackage.f() now is called, it will call mynewg() instead of g().

这将更改模块thirdpartypackage的全局g。因此,当调用thirdpartypackage.f()时,它将调用mynewg()而不是g()。

If this doesn't solve it, maybe g() is in fact imported from withing f(), or somthing. Then the solution is this:

如果这不能解决它,可能g()实际上是从f()或somthing导入的。然后解决方案是这样的:

import thirdpartypackage

def mynewg():
   pass

deg mynewf():
   mynewg()

thirdpartypackage.f = mynewf

That is, you override f() completely with a modified version that does what you want it to.

也就是说,你完全使用你想要它的修改版本覆盖f()。

#6


A function that's not executing doesn't have any locals; the local context is created when you run the function, and destroyed when it exits, so there's no "local namespace" to modify from outside the function.

没有执行的函数没有任何本地人;运行该函数时会创建本地上下文,并在它退出时销毁,因此没有“本地名称空间”可以从函数外部进行修改。

You can do something like this, though:

不过你可以这样做:

def f():
    g = [1]
    def func():
        print g[0]
    return func, g

f, val = f()
f()
val[0] = 2
f()

This uses an array to simulate a reference.

这使用数组来模拟引用。

#7


This seems to work

这似乎有效

def add_to_locals(l):
    l['newlocal'] = 1

add_to_locals(locals())
assert newlocal

#1


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.

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

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.

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

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:

要仅影响一个函数,您需要将func_globals指向其他位置。不幸的是,这是一个只读属性,但您可以通过使用相同的主体重新创建函数来执行您想要的操作,但是可以使用不同的全局命名空间:

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

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.

f现在将是缩进的,除了它将在提供的字典中查找全局变量。请注意,这会重新绑定整个全局命名空间 - 如果f确实存在变量,请确保您也提供它们。这也是相当hacky,并且可能不适用于除pypy之外的python版本。

#2


Since the function isn't invoked, it has no "local" stack frame, yet. The most simple solution is to use a global context:

由于未调用该函数,因此它没有“本地”堆栈帧。最简单的解决方案是使用全局上下文:

handler = None
def f():
    handler()

def g(): pass

handler = g

Or you could set g on the function object:

或者你可以在函数对象上设置g:

f.g = g

But I'm not sure how you can get the function object from within the function itself. If it was a method, you would use self.

但我不确定如何从函数本身中获取函数对象。如果它是一种方法,你会使用自我。

#3


Why don't you just add an argument to f() and pass a reference to g()?

为什么不直接向f()添加一个参数并传递对g()的引用?

def g():
    pass

def f(func):
    func()

f(g)

#4


I think you could solve the problem tackling it from a completely different point.
Functions are object, with their dictionaries; therefore, you can add g to f, and use it:

我认为你可以从完全不同的角度解决问题。功能是对象,带有词典;因此,您可以将g添加到f,并使用它:

def g():
   print "g"

def f():
    f.g()

f.g = g

#5


I assume you want to do this, because the function f is defined not by you, but by some other module. So you want to change how f() works. In particular, you want to change what is called when g is called.

我假设您要这样做,因为函数f不是由您定义的,而是由其他模块定义的。所以你想改变f()的工作方式。特别是,您希望更改调用g时调用的内容。

So I'll suggest this:

所以我建议这个:

import thirdpartypackage

def mynewg():
   pass

thirdpartypackage.g = mynewg

This will change the global g for the module thirdpartypackage. So when thirdpartypackage.f() now is called, it will call mynewg() instead of g().

这将更改模块thirdpartypackage的全局g。因此,当调用thirdpartypackage.f()时,它将调用mynewg()而不是g()。

If this doesn't solve it, maybe g() is in fact imported from withing f(), or somthing. Then the solution is this:

如果这不能解决它,可能g()实际上是从f()或somthing导入的。然后解决方案是这样的:

import thirdpartypackage

def mynewg():
   pass

deg mynewf():
   mynewg()

thirdpartypackage.f = mynewf

That is, you override f() completely with a modified version that does what you want it to.

也就是说,你完全使用你想要它的修改版本覆盖f()。

#6


A function that's not executing doesn't have any locals; the local context is created when you run the function, and destroyed when it exits, so there's no "local namespace" to modify from outside the function.

没有执行的函数没有任何本地人;运行该函数时会创建本地上下文,并在它退出时销毁,因此没有“本地名称空间”可以从函数外部进行修改。

You can do something like this, though:

不过你可以这样做:

def f():
    g = [1]
    def func():
        print g[0]
    return func, g

f, val = f()
f()
val[0] = 2
f()

This uses an array to simulate a reference.

这使用数组来模拟引用。

#7


This seems to work

这似乎有效

def add_to_locals(l):
    l['newlocal'] = 1

add_to_locals(locals())
assert newlocal