35

The description for co_names in the inspect module reads:

tuple of names of local variables

However in practice it appears that co_names is a tuple of global variable names while co_varnames is a tuple of local variable names (and argument names). For example:

a = 1

def f(b):
    c = a + b

print(f.__code__.co_varnames)  # prints ('b', 'c')
print(f.__code__.co_names)     # prints ('a',)

Furthermore in the docs for the dis module many instruction descriptions imply that co_names contains names of global variables. For example the LOAD_GLOBAL description reads:

Loads the global named co_names[namei] onto the stack.

Am I misunderstanding something here? Does co_names really contain "names of local variables"?

Edit 07/17/2017

As mentioned in the comments/answers this appears to be a documentation error. Bug issue filed here.

Edit 07/22/2017

Pull request to fix this documentation error approved and waiting to be merged.

Edit 06/06/2022

Pull request was merged 09/24/2021.

Alex
  • 18,484
  • 8
  • 60
  • 80

1 Answers1

29

As other's have already said, this seems to be a documentation error. The documentation for code objects clearly contradicts the documentation for inspect:

co_varnames is a tuple containing the names of the local variables (starting with the argument names); [...] co_names is a tuple containing the names used by the bytecode;

Also, accessing the attributes co_names and co_varnames of code objects conflicts with what was stated in inspect:

>>> def f():
...     a = 1
...     b = 2
... 
>>> f.__code__.co_names
()
>>> f.__code__.co_varnames
('a', 'b')

Furthermore, comments in the source code for CPython's compiler explicitly mention that co_varnames is for local variables:

PyObject *u_names;     /* all names */
PyObject *u_varnames; /* local variables */

The reason you don't see co_varnames is because the above code is initializing attributes for the compiler object that Python uses to compile code. u_names and u_varnames are both later passed into PyCode_New - the constructor for CPython code objects:

names = dict_keys_inorder(c->u->u_names, 0);
varnames = dict_keys_inorder(c->u->u_varnames, 0);

...

co = PyCode_New(..., names, varnames, ... );

And PyCode_New assigns names and varnames to the co_names and co_varnames attributes respectively:

Py_INCREF(names);
co->co_names = names;
Py_INCREF(varnames);
co->co_varnames = varnames;

If you already have not, I suggest filling out a bug report at bugs.python.org to let the Python development team know about this inconsistency in the documentation.

Christian Dean
  • 22,138
  • 7
  • 54
  • 87
  • @Alex Great. That's good to know. I'll check back up on the report later and update my answer if anything relevant surfaces. – Christian Dean Jul 17 '17 at 17:36
  • 1
    I think we are all agreed that `co_names` does not contain the local variables as documented, but it obviously does not match the contents of the `globals()` `dict` either and `a = 2; f = lambda: None; print(f.__code__.co_names)` results in an empty tuple for example @Alex – Chris_Rands Jul 18 '17 at 08:04
  • 1
    @Chris_Rands Agreed. As far as I can tell it contains the names of global variables used in the code object... Just as `co_freevars` only contains the names of free variables that are actually used in closures. – Alex Jul 18 '17 at 16:17
  • I guess this was seen in the PR - but we can note here too that it contains more than just the names of globals - if you use a dotted path like "pd.cut.foo" then "pd", "cut", "foo" are all included as separate names. – creanion Jun 04 '22 at 13:06