18
>>> import math >>> math.pi 3.141592653589793 >>> math.pi = 3 >>> math.pi 3 >>> import math >>> math.pi 3 

Initial question: Why can't I get math.pi back?

I thought import would import all the defined variables and functions to the current scope. And if a variable name already exists in current scope, then it would replace it.

Yes, it does replace it:

>>> pi = 3 >>> from math import * >>> pi 3.141592653589793 

Then I thought maybe the math.pi = 3 assignment actually changed the property in the math class(or is it math module?), which the import math imported.

I was right:

>>> import math >>> math.pi 3.141592653589793 >>> math.pi = 3 >>> from math import * >>> pi 3 

So, it seems that:
If you do import x, then it imports x as a class-like thing. And if you make changes to x.property, the change would persist in the module so that every time you import it again, it's a modified version.

Real question:

  1. Why is import implemented this way? Why not let every import math import a fresh, unmodified copy of math? Why leave the imported math open to change?
  2. Is there any workaround to get math.pi back after doing math.pi = 3 (except math.pi = 3.141592653589793, of course)?
  3. Originally I thought import math is preferred over from math import *. But this behaviour leaves me worrying someone else might be modifying my imported module if I do it this way...How should I do the import?
1
  • 1
    You may find Nick Coghlan's Traps for the Unwary a good (related) read. Commented Sep 18, 2013 at 4:05

3 Answers 3

13

Python only creates one copy of any given module. Importing a module repeatedly reuses the original. This is because if modules A and B imported C and D, which imported E and F, etc., C and D would get loaded twice, and E and F would get loaded 4 times, etc. With any but the most trivial of dependency graphs, you'd spend a few minutes loading redundant modules before running out of memory. Also, if A imported B and B imported A, you'd get stuck in a recursive loop and, again, run out of memory without doing anything useful.

The solution: Don't screw with the contents of other modules. If you do, that's an interpreter-wide change. There are occasionally situations where you'd want to do this, so Python lets you, but it's usually a bad idea.

Sign up to request clarification or add additional context in comments.

7 Comments

Ahh I see how it works out... If I do a from math import * it doesn't leave a pointer to the module so that I can't modify the module...thanks!
I don't understand your concern, octref, from your comments and question it seems that you assume you do the import for other coders to use.
@justhalf I'm asking this out of my curiosity... And, what else are all those access modifiers in OOP languages made for?
for Python, the OOP is only by convention. In Python there is no real access modifiers like in Java as some answers have highlighted. You can access every member of any module you imported, like you did. The convention is that the variables that should not be accessed from other module should be prepended with an underscore. So if you see a variable named _vocabulary in a module, that means the original writer doesn't want people to access that variable directly, but Python will still allow you to do that.
@justhalf: neither is access modifier in Java actually enforced at the bytecode level; even with Java, reflection can be used to muck with private members.
|
10

A module may be imported many times. An import statement just loads the reference from sys.modules. If the import statement also reloaded the module from disk, it would be quite slow. Modifying a module like this is very unusual and is only done under rare, documented circumstances, so there’s no need to worry.

How to reload a module:

>>> import imp >>> imp.reload(math) <module 'math' (built-in)> >>> math.pi 3.141592653589793 

6 Comments

imp.reload = lambda x: "Woops"
please don't tell people to reload modules. you really shouldn't ever need to
Thanks Josh... @jterrace for this case I think a reload is needed, as I'm having a very specific circumstance...
@jterrace: what about when you're debugging a module which you're changing between runs in ipython?
@octref: reload() should really only be used in interactive shell when you're modifying the source code of a module while issuing commands. If it's a running program, then you really shouldn't be using reload(). Instead, you should find and remove the offending module, or find a way to control its monkey patching behavior. The problem with reload() is that you can end up with multiple copies of the same variables/classes/methods that all works differently, incompatibly, and this will lead to all sorts of nightmare.
|
6

The import behavior is intended to allow modules to have state. For example, a module that runs initialization code may have all sorts of different behaviors based on what happens at init time (a good example is the os module, which transparently loads different versions of the path submodule depending on what OS you're on). The usual behavior exists to allow lots of different code to access the module without re-running the initialization over and over. Moreover, modules function sort of like static classes in other languages - they can maintain state and are often used as an alternative to global variables: eg, you might use the locale module to set local culture variables (currency format, etc) -- calling locale.setlocale in one part of your code and local.getlocale in another is a nice alternative to making a global variable.

Your example, of course, points out the weakness. One of the classic python principes is

We're all adults here

The language does not provide much of the privacy management features you'd find in, say, Java or C# which let the author lock down the contents of a module or class. You can, if you're feeling malicious (or just suicidal) do exactly the sort of thing done in your example: change pi to equal 3, or turn a function into a variable, or all sorts of other nasty stuff. The language is not designed to make that hard -- it's up to coders to be responsible.

@Josh Lee's answer shows how to use reload, which is the correct way of refreshing a module to it's disk-based state. The wisdom of using reload depends mostly on how much init code is in the module, and also on the web of other modules which import or are imported by the module in question.

2 Comments

Well that's one of the reason I like Python over Java. I guess maybe the point of Java's access modifiers lies more in team working on the same projects (so that you force your teammates to follow your API, not messing up with your implementation...)
absolutely - the whole access thing is designed for people working in the bowels of huge projects or corporations who will never meet or even hear of people using their stuff....

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.