Where is the globals?

Thanks to the discussion: Painful details of variable scope mixed with classes - #14 by eryksun, and after some tests, one question came to my mind.

Suppose I have one module “scratch.py”:

# scratch
def fibo(n):
   ...
class Fibonacci:
    def __init__(self, n):
       ...

and I wrote a test code like this:

import scratch

print(id(globals()), ":main")

## these are the same
F = scratch.Fibonacci(100)
print(id(F.__init__.__globals__))
print(id(scratch.fibo.__globals__))
print(id(eval("globals()", scratch.__dict__)))
print(id(eval("globals()", F.__dict__)), "?")

The result is for example:

2718657613760 :main
2718657663040
2718657663040
2718657663040
2718657620864 ?

Now my question is, “where did the last value come from? or where is the last globals?”.
I expected that the last value should be the same as the previous three.

You evaluated the expression globals() with globals set to F.__dict__, the dictionary that’s used for attributes of instance F. For example:

>>> F = Fibonacci(100)
>>> eval('globals()', F.__dict__) is F.__dict__
True
2 Likes

Thank you very much for your quick response!!
I must be misunderstanding something about eval in a dictionary… but I will think about it a bit more.

you are passing 2 args to eval(). what is that accomplishing? are you finding both of them to be obvious?

The second argument of eval is the globals namespace where the code is evaluated.

eval("globals()", F.__dict__)

My understanding this time is that the above expression does not mean F’s globals, but globals() evaluated in F.__dict__.
The globals() builtin function returns the namespace where the current code is evaluated, that is, F.__dict__.

globals ()
Return the dictionary implementing the current module namespace. For code within functions, this is set when the function is defined and remains the same regardless of where the function is called.
Built-in Functions — Python 3.10.13 documentation

It can be more clarified by this test:

>>> namespace = {}
>>> code = compile("x = globals()", "<string>", "exec")
>>> eval(code, namespace)
>>> namespace.keys()
dict_keys(['__builtins__', 'x'])
>>> (namespace['x'] is namespace)
True

Thank you again!