混合全局变量/参数与名为'top'的函数时的奇怪Python行为

21 投票
1 回答
4708 浏览
提问于 2025-04-16 04:47

下面这段代码(不是直接在解释器中运行,而是作为文件执行)

def top(deck):
    pass

def b():
    global deck

会在

SyntaxError: name 'deck' is local and global

python2.6.4 和

SyntaxError: name 'deck' is parameter and global

python 3.1 上产生错误。

python2.4 似乎可以接受这段代码,2.6.4 的交互式解释器也是如此。

这已经很奇怪了;为什么 'deck' 在一个方法里是全局变量,在另一个方法里却会冲突呢?

但事情变得更奇怪了。把 'top' 改成其他任何名字,问题就消失了。

有人能解释一下这种行为吗?我感觉我这里漏掉了什么很明显的东西。名字 'top' 是不是在某种程度上影响了作用域的内部机制?

更新

这确实看起来是 python 核心的一个 bug。我已经提交了一个 bug 报告

1 个回答

13

看起来这是在处理符号表时出现了一个错误。Python/symtable.c 里有一些代码(虽然有点复杂),确实把 'top' 当作一个特殊的标识符来处理:

if (!GET_IDENTIFIER(top) ||
    !symtable_enter_block(st, top, ModuleBlock, (void *)mod, 0)) {
    PySymtable_Free(st);
    return NULL;
}

然后稍后又有:

if (name == GET_IDENTIFIER(top))
    st->st_global = st->st_cur->ste_symbols;

在文件的更上面,有一个宏:

#define GET_IDENTIFIER(VAR) \
    ((VAR) ? (VAR) : ((VAR) = PyString_InternFromString(# VAR)))

这个宏使用了 C 语言的预处理器来初始化变量 top,让它变成一个包含变量名称的字符串。

我觉得符号表可能是用 'top' 这个名字来指代最顶层的代码,但我不知道为什么它不使用一个不会和真实变量冲突的名字。

如果我是你,我会把这个当作一个错误来报告。

撰写回答