26

I am learning Python and am still a beginner, although I have been studying it for about a year now. I am trying to write a module of functions which is called within a main module. Each of the functions in the called module needs the 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 I'm having a hard time understanding is why I get a name error when running main.py. I know that the variable pi becomes global to the main module upon import because wow can access it. I also know that cool becomes global to the main module upon import because I can print module1.cool and get <function cool at 0x02B11AF0>. So since cool is inside the global namespace of the main module, shouldn't the program first look inside the function cool for the variable pi, and then when it doesn't find it there, look inside main module for the variable pi and find it there?

The only way to get around this that I know of is to import the math module inside module1.py. I don't like the idea of that, though because it makes things more complicated and I am a fan of nice, simple code. I feel like I am close to grasping namespaces, but need help on this one. Thanks.

codeforester
  • 39,467
  • 16
  • 112
  • 140
SpencerAAA
  • 291
  • 1
  • 4
  • 10

5 Answers5

31

As the traceback shows, the problem isn't 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, in module1, there is no global name pi, because you haven't imported it there. When you do from math import * in main.py, that just imports everything from the math module's namespace into the main module's namespace, not into every module's namespace.

I think the key thing you're missing here is that each module has its own "global" namespace. This can be a bit confusing at first, because in languages like C, there's a single global namespace shared by all extern variables and functions. But once you get past that assumption, the Python way makes perfect sense.

So, if you want to use pi from module1, you have to do the from math import * in module1.py. (Or you could find some other way to inject it—for example, module1.py could do from main import *, or main.py could do module1.pi = pi, etc. Or you could cram pi into the magic builtins/__builtin__ module, or use various other tricks. But the obvious solution is to do the import where you want it imported.)


As a side note, you usually don't want to do from foo import * anywhere except the interactive interpreter or, occasionally, the top-level script. There are exceptions (e.g., a few modules are explicitly designed to be used that way), but the rule of thumb is to either import foo or use a limited from foo import bar, baz.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • 3
    Thank you for the response. If I understand you correctly then, when I call "cool" inside main.py, it first looks for pi in cool itself, but not finding it, it then looks for pi in module1.py, _not_ main.py, and obviously doesn't find it. So the searching for pi in this case is restricted to module1's global namespace, and cannot access main's global namespace. Is this right? – SpencerAAA Apr 09 '13 at 00:33
  • 1
    @SpencerAAA: That's a slight oversimplification, but only a slight one, and it's right for all the relevant parts. See [Naming and binding](http://docs.python.org/2/reference/executionmodel.html#naming-and-binding) for the full details. – abarnert Apr 09 '13 at 00:38
  • 3
    @SpencerAAA: Actually, you need a bit more than that section to get all the details. Briefly: at the time the `cool` definition is evaluated, Python determines that `pi` is not local (that is, free in the function's scope), and compiles the function into something like `print_item(globals()('pi'))`. (If you understand, or are willing to learn, CPython bytecode, try `import dis` and `dis.dis(cool)` to see _exactly_ what it does.) Then, that `globals`-lookup is what follows the rules for global lookup in Naming and binding. – abarnert Apr 09 '13 at 00:44
  • 5
    Thanks, that is a good reference. I think what I misunderstood is I thought that the program was making a copy of "cool" and putting it in the main module as if it were any other function in the main module - that is, as if I had just copied the code into the main module. But I guess it is still just a reference to the "cool" in module1.py, not a copy. – SpencerAAA Apr 09 '13 at 01:08
  • 4
    @SpencerAAA: Yeah, that's the key difference between `import` and `execfile`, and part of what "Namespaces are one honking great idea" in the Zen means. You can have a _different_ `pi` in `main.py` and `module1.py`, and they don't interfere with each other. (That may not seem useful for `pi`, which obviously should always mean the same thing unless you're porting to another universe, but it's very useful for, e.g., functions named `parse_string` or `open`.) – abarnert Apr 09 '13 at 01:38
  • Hi. Instead of import module1, if the user had done 'from module1 import cool' then the function definition of cool will have come in the global namespace of main.py which also has got pi. Now would the code work? What is this concept called? Can you please point me to reference link – variable Oct 17 '19 at 15:48
6

"Explicit is better than implicit" is a design decision that was made by the creators of Python (launch python and run import this).

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


You'll have to import the math module in explicitly whenever you want to use it - that's just how Python works.

Also, you should avoid from X import *-style imports, that's bad practice too. Here, you could do: from math import pi.

Thomas Orozco
  • 53,284
  • 11
  • 113
  • 116
  • Instead of import module1, if the user had done 'from module1 import cool' then the function definition of cool will have come in the global namespace of main.py which also has got pi. Now would the code work? Can you please point me to reference link which clears about this topic? – variable Oct 18 '19 at 04:13
2

As others have said, there isn't actually a global pi in your module1. A good solution for you is this, which only imports pi once from math and explicitly ensures that the pi you're getting is the one from module1:

main.py:

import module1

def wow():
    print module1.pi

wow()
module1.cool()

module1.py:

from math import pi

def cool():
    print pi
askewchan
  • 45,161
  • 17
  • 118
  • 134
  • Hi. Instead of import module1, if the user had done 'from module1 import cool' then the function definition of cool will have come in the global namespace of main.py which also has got pi. Now would the code work? What is this concept called? Can you please point me to reference link – variable Oct 17 '19 at 15:50
  • @variable, my understanding of the various imports are that they have no effect on the import process nor on the variable scoping. In both cases the entire file `module1.py` is processed, but instead of having a variable `module1` left at the end, you just keep `cool`, causing you to lose access to the other objects in the module. I believe you can think of it as equivalent to `import module1`; `cool = module1.cool`; `del module1`. – askewchan Oct 18 '19 at 16:30
  • So when cool = module1.cool, why doesnt it use the pi that exists in the main.py namespace? What is this concept called and is there any reference link please? I thought that from import would bring the entire function definition in local namespace – variable Oct 18 '19 at 16:45
  • 1
    @variable, the behavior of a function does not depend on what it is named nor where it is evaluated; it depends on where it is defined. The importing it does not import the definition, but rather the function object. For reading, I suggest [Python Tutorial 9.2. Python Scopes and Namespaces](https://docs.python.org/3/tutorial/classes.html#python-scopes-and-namespaces) or the more technical [Python Reference 4.2. Naming and binding](https://docs.python.org/3/reference/executionmodel.html). – askewchan Feb 07 '20 at 17:19
2

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

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

and then you can simply call the function with cool() rather than module1.cool(). Within cool(), the variable pi will behave like a global, as the OP had originally expected.

In a nutshell, this is simply hiding a function definition 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 a proper namespaces) is probably a mistake as you don't generally want to keep too many things within a single global namespace.

But for simple cases (like using Python as a shell script) exec gives you a simple and concise way to hide shared functions while letting them share the global namespace. Just note that in this case you might want to give extra thought to how you name your functions (e.g. use v1_cool and v2_cool to keep track of different versions since you can't do v1.cool and v2.cool).

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

JohnE
  • 29,156
  • 8
  • 79
  • 109
  • Instead of import module1, if the user had done 'from module1 import cool' then the function definition of cool will have come in the global namespace of main.py which also has got pi. Now would the code work? What is this concept called? Can you please point me to reference link – variable Oct 18 '19 at 04:15
1

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

Saucier
  • 4,200
  • 1
  • 25
  • 46
  • Instead of import module1, if the user had done 'from module1 import cool' then the function definition of cool will have come in the global namespace of main.py which also has got pi. Now would the code work? What is this concept called? Can you please point me to reference link – variable Oct 18 '19 at 04:14