Each module has its own globals. Python is behaving exactly as expected. Updating globalEx1
's a
to point to something else isn't going to affect where globalEx2
's a
is pointing.
There are various ways around this, depending on exactly what you want.
- re-import
a
after the setvalue()
call
return a
and assign it, like a = setvalue()
.
import globalEx1
and use globalEx1.a
instead of a
. (Or use import globalEx1 as
and a shorter name.)
- pass
globalEx2
's globals()
as an argument to setvalue
and set the value on that instead.
- make
a
a mutable object containing your value, like a list, dict or types.SimpleNamespace
, and mutate it in setvalue
.
- use
inspect
inside setvalue
to get the caller's globals from its stack frame. (Convenient, but brittle.)
Last option looks suitable for me.. it will do the job with minimal code change but can I update globals of multiple modules using same way? or it only gives me the caller's globals?
Option 6 is actually the riskiest. The caller itself basically becomes a hidden parameter to the function, so something like a decorator from another module can break it without warning. Option 4 just makes that hidden parameter explicit, so it's not so brittle.
If you need this to work across more than two modules, option 6 isn't good enough, since it only gives you the current call stack. Option 3 is probably the most reliable for what you seem to be trying to do.
How does option 1 work? I mean is it about running again -> "from globalEx1 import *" because I have many variables like 'a'.
A module becomes an object when imported the first time and it's saved in the sys.modules
cache, so importing it again doesn't execute the module again. A from ... import
(even with the *
) just gets attributes from that module object and adds them to the local scope (which is the module globals if done at the top level, that is, outside of any definition.)
The module object's __dict__
is basically its globals, so any function that alters the module's globals will affect the resulting module object's attrs, even if it's done after the module was imported.
We cannot do from 'globalEx1 import *' from a python function, any alternative to this?
The star syntax is only allowed at the top level. But remember that it's just reading attributes from the module object. So you can get a dict of all the module attributes like
return vars(globalEx1)
This will give you more than *
would. It doesn't return names that begin with an _
by default, or the subset specified in __all__
otherwise. You can filter the resulting dict with a dict comprehension, and even .update()
the globals dict for some other module with the result.
But rather than re-implementing this filtering logic, you could just use exec to make it the top level. Then the only weird key you'd get is __builtins__
namespace = {}
exec('from globalEx1 import *', namespace)
del namespace['__builtins__']
return namespace
Then you can globals().update(namespace)
or whatever.
Using exec
like this is probably considered bad form, but then so is import *
to begin with, honestly.