有什么方法可以修改本地词典吗?

Cas*_*ash 14 python local-variables

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

警告

不应修改此词典的内容; 更改可能不会影响解释器使用的局部变量的值.

不幸的是,exec在Python 3.0中也有同样的问题.这有什么办法吗?

用例

考虑:

@depends("a", "b", "c", "d", "e", "f")
def test():
    put_into_locals(test.dependencies)
Run Code Online (Sandbox Code Playgroud)

depends将其参数中提供的字符串存储在列表中test.dependences.这些字符串是字典中的键d.我希望能够编写,put_into_locals以便我们可以将值拉出d并将它们放入本地.这可能吗?

Unk*_*own 14

我刚刚测试了exec,它适用于Python 2.6.2

>>> def test():
...     exec "a = 5"
...     print a
...
>>> test()
5
Run Code Online (Sandbox Code Playgroud)

如果您使用的是Python 3.x,则它不再起作用,因为locals在运行时被优化为数组,而不是使用字典.

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

http://bugs.python.org/issue4831

如果没有几个结果,则无法动态修改函数的局部函数:通常,函数局部函数不存储在字典中,而是存储在数组中,其索引在编译时从已知语言环境确定.这至少与exec添加的新本地人发生冲突.旧的exec语句规避了这一点,因为编译器知道如果函数中没有发生全局/局部因子的exec,那么该命名空间将"未经优化",即不使用本地数组.由于exec()现在是一个普通函数,编译器不知道"exec"可能绑定到什么,因此无法特别处理.

  • @Casebash,它可能是可能的,它只需要字节码黑客或 Python 2.x (2认同)

S.L*_*ott 7

局部变量由赋值语句修改.

如果你有字符串的字符串键,请不要使它们成为局部变量 - 只需将它们用作字典键.

如果你绝对必须 有局部变量这样做.

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 )
Run Code Online (Sandbox Code Playgroud)

这将填充你的字典中的一些局部变量而不做任何神奇的事情.

  • 这是一个有趣的想法.但是,有许多应用程序,其中字典实际上包含许多其他变量(`aFunction()`不需要),这使得`aFunction()`的当前定义中断.一个有用的概括是:`aFunction(a,b,c,d,e,f,**kwargs)`. (5认同)
  • @S.Lott:让我重新说一下我的观点:当someDictWithKeys_a_b_c_d_e_f`包含比这几个变量更多的键时,有什么突破是签名`def aFunction(a,b,c,d,e,f)`,这是执行时的典型情况复杂的科学计算(整个计算使用的变量多于它调用的大多数函数).正如我所指出的那样,`def aFunction(a,b,c,d,e,f,**kwargs)`是解决这种情况的一种方便方法. (4认同)
  • @S.Lott:用'aFunction(**{'a':0,'b':1,'c':2,'d':3,'e':4)运行你的答案代码(我赞成) ,'f':5,'g':6})`这将准确地说明为什么我的评论对StackOverflow读者有用.在现实生活中的科学计算中,字典通常包含的变量多于单独发送给每个函数的变量. (3认同)
  • 每个函数都使用参数的子集,您不希望编写一堆样板来仅提取真正需要的部分.当函数需要更多参数时,您不希望修改调用者,并且当模型的不同部分需要引入新参数时,您不希望修改内部函数. (3认同)
  • @S.Lott:这样做的目的是为了更方便地访问dict或object成员.这个想法是像`(a**2 + b)*exp(c*d/e)`这样的公式比`(na**2 + nb)*exp(nc*nd/ne)更容易阅读.对于某些`n`(也许只是包含包含相关变量的dict).至于"糟糕的设计",假设你有一些参数来决定一组函数的形状.例如,这些可以是描述状态方程和气体的其他性质的材料参数. (2认同)

Gle*_*ard 5

这是不可能的。我认为这是为了以后进行性能优化。Python 字节码通过索引而不是名称引用局部变量;如果 locals() 被要求是可写的,它可能会阻止解释器实现一些优化,或者使它们变得更加困难。

我相当肯定您不会找到任何保证您可以像这样编辑本地人的核心 API,因为如果该 API 可以做到,那么 locals() 也不会受到此限制。

不要忘记所有本地变量在编译时都必须存在;如果在编译时引用未绑定到本地的名称,则编译器会假定它是全局的。编译后不能“创建”本地人。

请参阅此问题以获取一种可能的解决方案,但这是一个严重的问题,您真的不想这样做。

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

@depends("a", "b", "c", "d", "e", "f")
def test():
    put_into_locals(test.dependencies)
Run Code Online (Sandbox Code Playgroud)

"test.dependencies"不是指“f.dependencies”,其中 f 是当前函数;它引用了实际的全局值“test”。这意味着如果您使用多个装饰器:

@memoize
@depends("a", "b", "c", "d", "e", "f")
def test():
    put_into_locals(test.dependencies)
Run Code Online (Sandbox Code Playgroud)

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