在Python 2.6中访问外部作用域

8 投票
6 回答
11721 浏览
提问于 2025-04-16 10:24

假设我有一些变量在某个范围内,而这个范围里的一个函数想要改变一些不可变的变量:

def outer():
    s = 'qwerty'
    n = 123
    modify()

def modify():
    s = 'abcd'
    n = 456

有没有办法访问外部范围的变量呢?就像Python 3中的nonlocal变量那样。

当然,我可以这样做:s,n = modify(s,n),但是如果我需要一些通用的“注入”操作,让它在那儿执行,并且能够重新赋值给任意变量呢?

我考虑到性能,所以如果可能的话,不想使用eval和堆栈帧检查这些方法 :)


更新:这是不可能的。就这样。不过,有一些方法可以访问外部范围的变量:

  1. 使用全局变量。顺便提一下,func.__globals__是一个可变的字典;)
  2. 把变量存储在字典、类实例或其他可变容器中。
  3. 把变量作为参数传入,然后以元组的形式返回它们:a,b,c = innerfunc(a,b,c)
  4. 注入其他函数的字节码。这可以通过byteplay这个Python模块实现。

6 个回答

7

在函数外面定义变量,并使用 global 关键字。

s, n = "", 0

def outer():
    global n, s
    n = 123
    s = 'qwerty'
    modify()

def modify():
    global n, s
    s = 'abcd'
    n = 456
7

有时候我会看到这样的代码。里面有一个嵌套的函数,它修改了一个可变对象,而不是给一个nonlocal变量赋值:

def outer():
    s = [4]
    def inner():
        s[0] = 5
    inner()
3

这并不是nonlocal的工作方式。它并不提供动态作用域(这其实是个大麻烦,几乎没有什么用处,甚至比一般的“坏”特性还要少)。它只是修正了词法作用域。

总之,你想的那种做法是行不通的(我觉得这其实是件好事)。连个简单的黑科技都没有(顺便说一下:这种黑科技并不被反对,因为它们通常性能稍差!)。所以就别想这个了,去好好解决真正的问题吧(你没有提到具体问题,所以我们也没法说什么)。

你能做到的最接近的方式是定义一个对象,把你想共享的所有东西都放在里面,然后明确地传递这个对象(比如,创建一个类并使用self,就像另一个回答中提到的那样)。不过这样做在很多地方都比较麻烦,而且还是有点黑科技(虽然比动态作用域要好,因为“显式比隐式好”)。

撰写回答