The following code (not directly in an interpreter, but execute as file)
def top(deck):
pass
def b():
global deck
produces the error
It looks like it is a bug in the symbol table handling. Python/symtable.c has some code that (although somewhat obfuscated) does indeed treat 'top' as a special identifier:
if (!GET_IDENTIFIER(top) ||
!symtable_enter_block(st, top, ModuleBlock, (void *)mod, 0)) {
PySymtable_Free(st);
return NULL;
}
followed somewhat later by:
if (name == GET_IDENTIFIER(top))
st->st_global = st->st_cur->ste_symbols;
Further up the file there's a macro:
#define GET_IDENTIFIER(VAR) \
((VAR) ? (VAR) : ((VAR) = PyString_InternFromString(# VAR)))
which uses the C preprocessor to initialise the variable top
to an interned string with the name of the variable.
I think the symbol table must be using the name 'top' to refer to the top level code, but why it doesn't use something that can't conflict with a real variable I have no idea.
I would report it as a bug if I were you.