Namespaces with importing modules

I am learning Python and still a beginner, although I have been studying it for about a year now. I am trying to write a function module that is called in the main module. Each of the functions in the called module needs a math module to run. I am wondering if there is a way to do this without importing the math module inside the called module. Here is what I have:

main.py :

 from math import * import module1 def wow(): print pi wow() module1.cool() 

module1.py :

 def cool(): print pi 

When running main.py I get:

 3.14159265359 Traceback (most recent call last): File "Z:\Python\main.py", line 10, in <module> module1.cool() File "Z:\Python\module1.py", line 3, in cool print pi NameError: global name 'pi' is not defined 

What is hard for me to understand is why I get a name error when running main.py I know that the pi variable becomes global for the main module upon import, because wow can access it. I also know that cool becomes global for the main module upon import, because I can print module1.cool and get <function cool at 0x02B11AF0> . Since cool is located inside the global namespace of the main module, the program should not first enter the cool function for the variable pi , and then, when it does not find it, look inside main for the variable pi and find it there?

The only way around this that I know of is to import the math module inside module1.py . I do not like the idea of โ€‹โ€‹this, though, because it complicates the situation, and I am a fan of pleasant, simple code. I feel like I'm close to understanding namespaces, but I need help with this. Thank.

+16
python import module namespaces local
Apr 08 '13 at 22:17
source share
5 answers

As the trace shows, the problem is not in main.py , but in module1.py :

 Traceback (most recent call last): File "Z:\Python\main.py", line 10, in <module> module1.cool() File "Z:\Python\module1.py", line 3, in cool print pi NameError: global name 'pi' is not defined 

In other words, there is module1 global name pi in module1 because you did not import it there. When you do from math import * in main.py , it simply imports everything from the math module namespace into the main module namespace, and not into each module namespace.

I think the key thing that you are missing here is that each module has its own โ€œglobalโ€ namespace. This can be a little confusing at first, because in languages โ€‹โ€‹like C, there is one global namespace shared by all extern variables and functions. But once you overcome this assumption, the Python path makes sense.

So, if you want to use pi from module1 , you need to do from math import * in module1.py . (Or you could find some other way to insert it - for example, module1.py could do from main import * , or main.py could do module1.pi = pi , etc. Or you could paste pi into magic builtins / __builtin__ or use other tricks. But the obvious solution is to make import where you want to import it.)




As a side note, you usually don't want to do from foo import * anywhere except an interactive interpreter, or sometimes a top-level script. There are exceptions (for example, several modules are explicitly intended for use in this way), but the rule of thumb applies to either import foo or the restricted from foo import bar, baz .

+22
Apr 08 '13 at 22:28
source share

"Explicit is better than implicit" is a design solution created by the creators of Python (running python and running import this ).

Therefore, when you run module1.cool() , Python will not look for undefined pi in the main module.




You will need to import the math module explicitly when you want to use it - this is how Python works.

In addition, you should avoid importing from X import * -style, which is also bad. Here you can do: from math import pi .

+6
Apr 08 '13 at 22:21
source share

As others have said, on your module1 there is actually no global pi . A good solution for you is that only one of pi imports only math and explicitly guarantees that the pi you get is one of module1 :

main.py :

 import module1 def wow(): print module1.pi wow() module1.cool() 

module1.py :

 from math import pi def cool(): print pi 
+2
Apr 08 '13 at
source share

The simple exec (python 3) or execfile (python 2) approach mentioned in @abarnert's comments may be useful for some workflows. All that is needed is to replace the import string:

 exec( open("module1.py").read() ) # python 3 

and then you can just call the function using cool() and not module1.cool() . Inside cool() , the pi variable will behave as global, as the OP originally expected.

In a nutshell, it's just hiding the definition of a function that would otherwise appear at the top of your main program and has both advantages and disadvantages. For large projects with multiple modules and imports, using exec (instead of the correct namespaces) is probably a mistake, since you usually don't want to store too many things in one global namespace.

But for simple cases (like using Python as a shell script), exec provides a simple and concise way to hide common functions, allowing them to share a global namespace. Just note that in this case, you might think about how to name your functions (for example, use v1_cool and v2_cool to track different versions, since you cannot use v1.cool and v2.cool ).

One less obvious drawback of using exec here is that errors in executable code may not display the error line number, although you can work around this: how to get the error line number from exec or execfile in Python

+2
Jul 11 '18 at 7:55
source share

Inside the module, you can simply define from math import pi , which will only import pi from math, but not the entire math module.

+1
Apr 08 '13 at 22:24
source share



All Articles