I have a problem with globals using method of class from my testmodule
Example: Text of my test module:
cat ./testmodule.py
class testclass(object):
def __init__(self):
self.testfunc()
def testfunc(self):
print(' '.join(globals()).split(' '))
Text of my test class the same:
class testclass(object):
def __init__(self):
self.testfunc()
def testfunc(self):
print(' '.join(globals()).split(' '))
Text of my test func, nothing new:
def testfunc():
print(' '.join(globals()).split(' '))
And go to test it.
Python 3.6.6 (default, Aug 13 2018, 18:24:23)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>>
>>> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa='a'
>>>
>>> import testmodule
>>>
>>> class testclass(object):
... def __init__(self):
... self.testfunc()
...
... def testfunc(self):
... print(' '.join(globals()).split(' '))
...
>>> def testfunc():
... print(' '.join(globals()).split(' '))
Everything is ready, let's test
>>> testfunc()
['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'testmodule', 'testclass', 'testfunc']
Variable exist
>>> testclass.testfunc(testclass)
['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'testmodule', 'testclass', 'testfunc']
The same result, variable exist
>>> testmodule.testclass.testfunc(testclass)
['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__file__', '__cached__', '__builtins__', 'testclass']
>>>
Variable is lost.
How can i get the same result from testmodule like from testclass and testfunc?
Expanding on @chepner's comment: globals()
returns the module-level variables of the current module only.
testfunc()
in the REPL, it is defined as __main__.testfunc
and invoking globals()
returns essentially __main__.__dict__
.testmodule
, it is defined as testmodule.testfunc
and globals()
returns testmodule.__dict__
.If you want testfunction
to access globals of another module, you need to ensure that globals()
is called in the lexical scope of the module. The easiest was is to extend testfunction
to expect a dictionary as argument:
## testmodule.py
def testfunc(globals_):
print(globals_)
## REPL or other module
import testmodule
testmodule.testfunc(globals())
__main__
isn't defined by default. You need to import __main__
before you can use it. But you can see that the current module is named __main__
from the variable __name__
.
When you run python somescript.py
, the contents of the file are executed as the __main__
module, not as a somescript
module.
Python has closures, and functions inside modules behave essentially like closures over the module scope – so I would have expected globals()
to be a member of every module. Then the following would have yielded the expected result:
%% testmodule.py
def testfunc(globals_):
print(_globals())
%% REPL
import testmodule
testmodule.testfunc(globals)
but again, this returns the globals of only the testmodule. Instead globals
is defined only in __builtin__
, and seems to use the scope of the caller as hidden argument. As a consequence:
## REPL
import testmodule
testmodule.testfunc(globals) # prints testmodule.__dict__
testmodule.testfunc(lambda: globals()) # prints __main__.__dict__
Normally expect f
and lambda: f()
to have the same result.
You can't rely on somemodule.__dict__
to be defined. A module may actually choose to return some wrapper object instead of a normal module object, when you import it. Actually, nothing even enforces that somemodule
has typical module semantics! E.g. try the module:
## somemodule.py -- Please don't actually do this.
import sys
sys.modules["somemodule"] = "not a module"
## REPL
>>> import somemodule
>>> somemodule
'not a module'
A real-world example for such changes would be os.path
:
>>> import os.path
>>> os.path
<module 'ntpath' from 'C:\tools\msys64\mingw64\lib\python2.7\ntpath.pyc'>