在Python中修改当地人

locals是一个内置的函数,返回一个本地值的字典。 该文件说:

警告

这本词典的内容不应该修改; 更改可能不会影响解释器使用的局部variables的值。

不幸的是,exec在Python 3.0中有相同的问题。 有什么办法吗?

用例

考虑:

@depends("a", "b", "c", "d", "e", "f") def test(): put_into_locals(test.dependencies) 

依赖将其参数中提供的string存储在列表test.dependences 。 这些string是字典中的键。 我希望能够写put_into_locals这样我们就可以将值从d提取出来并放入当地人。 这可能吗?

我只testing了exec,它在Python 2.6.2中起作用

 >>> def test(): ... exec "a = 5" ... print a ... >>> test() 5 

如果您使用的是Python 3.x,那么它就不能工作了,因为在运行时本地语言被优化为一个数组,而不是使用字典。

当Python检测到“exec语句”时,它将强制Python将本地存储从数组切换到字典。 但是由于“exec”是Python 3.x中的一个函数,编译器无法做出区分,因为用户可能已经做了类似“exec = 123”的操作。

http://bugs.python.org/issue4831

要dynamic地修改函数的局部性是不可能的,没有几个后果:通常,函数局部variables不是存储在字典中,而是一个数组,其索引是在编译时从已知的语言环境中确定的。 这至less与exec添加的新本地人相冲突。 旧的exec语句绕过了这个,因为编译器知道如果一个没有globals / locals args的exec在一个函数中出现,那这个名字空间将是“unoptimized”,即不使用locals数组。 由于exec()现在是一个正常的函数,编译器不知道“exec”可能会绑定什么,因此不能正确处理。

局部variables由赋值语句修改。

如果您有stringstring,请不要将它们变成局部variables – 只要将它们用作字典键即可。

如果你绝对必须有局部variables做到这一点。

 def aFunction( a, b, c, d, e, f ): # use a, b, c, d, e and f as local variables aFunction( **someDictWithKeys_a_b_c_d_e_f ) 

这将填充你的字典中的一些局部variables,而不做任何神奇的事情。

这是不可能的。 我想这是为了稍后的性能优化。 Python字节码通过索引而不是名字来引用当地人; 如果本地()需要是可写的,它可能会阻止解释器执行一些优化,或使其更加困难。

我相当肯定,你不会find任何核心的API来保证你可以像这样编辑locals,因为如果这个API可以做,locals()也不会有这个限制。

不要忘记,所有的本地人都必须在编译时存在; 如果在编译时引用一个没有绑定到本地的名字,编译器会认为它是全局的。 编译后不能“创build”本地文件。

看到这个问题的一个可能的解决scheme,但这是一个严重的黑客,你真的不想这样做。

请注意,您的示例代码存在一个基本问题:

 @depends("a", "b", "c", "d", "e", "f") def test(): put_into_locals(test.dependencies) 

"test.dependencies"不是指“f.dependencies”,其中f是当前函数; 它是参考实际的全球价值“testing”。 这意味着如果你使用多个装饰器:

 @memoize @depends("a", "b", "c", "d", "e", "f") def test(): put_into_locals(test.dependencies) 

它将不再起作用,因为“testing”是memoize的包装function,而不是依赖的。 Python 真的需要一种方法来引用“当前正在执行的函数”(和类)。

我将它存储在一个variables中:

 refs = locals() def set_pets(): global refs animals = ('dog', 'cat', 'fish', 'fox', 'monkey') for i in range(len(animals)): refs['pet_0%s' % i] = animals[i] set_pets() refs['pet_05']='bird' print(pet_00, pet_02, pet_04, pet_01, pet_03, pet_05 ) >> dog fish monkey cat fox bird 

如果你想在把它放入locals()之前testing你的dict:

 def set_pets(): global refs sandbox = {} animals = ('dog', 'cat', 'fish', 'fox', 'monkey') for i in range(len(animals)): sandbox['pet_0%s' % i] = animals[i] # Test sandboxed dict here refs.update( sandbox ) 

MacOS Sierra上的Python 3.6.1

我不确定它是否受到相同的限制,但是可以通过检查模块直接引用当前帧(并从那里,本地variables字典):

 >>> import inspect >>> inspect.currentframe().f_locals['foo'] = 'bar' >>> dir() ['__builtins__', '__doc__', '__name__', '__package__', 'foo', 'inspect'] >>> foo 'bar'