3

I'm trying to reproduce a bug that I've encountered that shows this:

NameError: global name 'sdrent' is not defined

However, if I open up the interpreter and type in sdrent, I get the following error:

>>> sdrent
NameError: name 'sdrent' is not defined

What is the difference between NameError: global name... and NameError: name..., and how would I reproduce the former?

user2357112
  • 260,549
  • 28
  • 431
  • 505
David542
  • 104,438
  • 178
  • 489
  • 842

2 Answers2

2

CPython has two opcodes used for global variable lookups, LOAD_GLOBAL and LOAD_NAME. LOAD_NAME looks for a local variable before a global variable, while LOAD_GLOBAL goes straight to globals. LOAD_NAME is primarily useful for class statements, but in the absence of a global declaration, the compiler also happens to emit LOAD_NAME for global variable lookups at module level.

Back before Python 3.4, LOAD_GLOBAL used to say global name 'whatever' is not defined when the lookup fails, and LOAD_NAME used to say name 'whatever' is not defined. This got changed when someone argued that "global" was confusing for cases where someone mistyped a local variable name.

You're on Python 2.7. When you run a variable lookup for a nonexistent name at top level, you get the LOAD_NAME error message, but inside a function, you get the LOAD_GLOBAL error message, which still says "global" on Python 2.

user2357112
  • 260,549
  • 28
  • 431
  • 505
1

It seems this happens in the context of a function or method, where the LEGB stops at G(lobal), knowing the builtins already and exits/complains at that scope.

For example, to reproduce:

>>> def hi():
...     sdrent
...
>>> hi()
NameError: global name 'sdrent' is not defined

Or even simpler:

>>> (lambda: sdrent)()
NameError: global name 'sdrent' is not defined

And in a class method:

>>> class X:
        def __call__(_): sdrent
>>> X()()
NameError: global name 'sdrent' is not defined
David542
  • 104,438
  • 178
  • 489
  • 842
  • 1
    This doesn't have anything to do with "knowing the builtins already". The lookup does actually continue to the built-ins, because even if it tried to cache the fact that there's no `sdrent` built-in, something could have added an `sdrent` to the built-ins in the meantime. – user2357112 Feb 07 '21 at 06:04
  • @user2357112supportsMonica I see, maybe I should add that in to clarify that it does check that, though the error message doesn't mention that. – David542 Feb 07 '21 at 06:05
  • 1
    (There is actually a global/builtin variable cache optimization on newer Python versions based on dict version identifiers, but it only triggers for cases where the lookup succeeds, not for NameErrors.) – user2357112 Feb 07 '21 at 06:11