I've been trying to use the python builtin inspect.getclosurevars
to identify global variables that sneak into functions, with the goal of providing users a way to guard against this behavior in jupyter notebooks, where scope management can be very difficult.
However, I noticed that object attributes are classified either as unbound or globals, depending on whether another object has been declared with the attribute's name or not.
In both of the following cases, I did not expect 'name'
or 'age'
to show up in any of these lists. It's not what I understand to be an unbound variable:
In [1]: import inspect
In [2]: def get_persons_name(person):
...: return person.name
...:
In [3]: inspect.getclosurevars(get_persons_name)
Out[3]: ClosureVars(nonlocals={}, globals={}, builtins={}, unbound={'name'})
And it's certainly not a global:
In [4]: age = 4
...:
...: def get_persons_age(person):
...: return person.age
...:
In [5]: inspect.getclosurevars(get_persons_age)
Out[5]: ClosureVars(nonlocals={}, globals={'age': 4}, builtins={}, unbound=set())
Is this a bug in inspect? Or am I misunderstanding something fundamental? If so, is there a better way to distinguish between attributes and true global/unbound variables?
I'm using python 3.7.6, tested on a jupyter notebook and ipython & python prompts, macos & ubuntu.
That's a bug. Python issue 36697, reported in 2019 and still not fixed. inspect.getclosurevars
is looking in the code object's co_names
to find global name references, but co_names
isn't just globals. It includes attributes and a few other things, like names used in import
statements. (Ignore what the inspect
docs say about co_names
- the code object field docs have been wrong for ages.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With