accessing variable of the __main__ module

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Sat Mar 20 09:05:41 EDT 2010


On Sat, 20 Mar 2010 13:16:08 +0100, News123 wrote:

> Hi,
> 
> 
> I wondered about the best way, that a  module's function could determine
> the existance and value of variables in the __main__ module.
> 
> 
> What I came up with is:
> ########### main.py ##########
> import mod
> A = 4
> if __name__ == "__main__": mod.f()
> ########### mod.py ##########
> def f():
>     try:
>         from __main__ import A
>     except ImportError as e:
>         A = "does not exist"
>     print "__main__.A" ,A
> 
> Is there anything better / more pythonic?


First problem:

You try to import from "__main__", but the other module is called "main". 
__main__ is a special name, which Python understands as meaning "this 
module that you are in now". For example:

$ cat test_main.py
x = "something special"
import __main__  # magic alias for this module
print __main__.x

$ python test_main.py
something special

So inside "mod.py", the line "from __main__ import A" tries to import A 
from mod.py, not from main.py. You need to say "from main import A" 
instead.

But if you do this, it creates a second problem: you have a circular 
import, which is generally considered a Bad Thing. The problem is that:

(1) module main tries to import module mod
(2) module mod tries to import module main
(3) but main is still waiting for mod to be imported

Now, in your case you escape that trap, because the import is inside a 
function, so it doesn't occur until you call the function. But it is 
still considered poor practice: it is best to avoid circular imports 
unless you really, really need them.


The question is, why does module mod.py care what is happening in 
main.py? It is better for mod.py to be self-contained, and not care about 
main.py at all. If it needs A, let the caller pass A to it:

########### main.py ##########
import mod
A = 4
if __name__ == "__main__":
    mod.f(__name__, A)

########### mod.py ##########
def f(caller, A):
    print "%s.A: %s" % (caller, A)



-- 
Steven



More information about the Python-list mailing list