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

最初的问题:为什么我不能math.pi回来?

我认为import会将所有定义的变量和函数导入当前范围。如果当前范围内已经存在变量名,那么它将替换它。

是的,它确实取代了它:

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

然后我想也许math.pi = 3分配实际上改变了math class(或者是math module?)中的属性,这是import math导入的。

我是对的:

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

所以,似乎:
如果你这样做import x,那么它会x作为类类的东西导入。如果您对 x.property 进行更改,该更改将保留在模块中,因此每次您再次导入它时,它都是一个修改后的版本。

真正的问题

  1. 为什么要import这样实现?为什么不让每个import math导入一个新的、未修改的副本math?为什么要离开进口math开放改变?
  2. 做完之后有什么解决方法可以math.pi恢复math.pi = 3(当然,除了math.pi = 3.141592653589793)?
  3. 本来我以为import math是首选from math import *。但是这种行为让我担心如果我这样做,其他人可能会修改我的导入模块......我应该怎么做import
4

3 回答 3

13

Python 只创建任何给定模块的一个副本。导入一个模块会重复使用原始模块。这是因为如果模块 A 和 B 导入 C 和 D,其中导入 E 和 F 等,C 和 D 将被加载两次,E 和 F 将被加载 4 次,等等。图表,您会在内存不足之前花费几分钟加载冗余模块。此外,如果 A 导入 B 和 B 导入 A,您将陷入递归循环,并且再次耗尽内存而没有做任何有用的事情。

解决方案:不要乱用其他模块的内容。如果你这样做了,那就是口译员范围内的变化。在某些情况下,您希望这样做,因此 Python 允许您这样做,但这通常不是一个好主意。

于 2013-09-18T03:56:19.487 回答
10

一个模块可能会被多次导入。一个import语句只是从 加载引用sys.modules。如果该import语句还从磁盘重新加载模块,它会很慢。像这样修改一个模块是非常不寻常的,并且只在极少数有记录的情况下进行,因此无需担心。

如何重新加载模块:

>>> import imp
>>> imp.reload(math)
<module 'math' (built-in)>
>>> math.pi
3.141592653589793
于 2013-09-18T03:50:55.943 回答
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.

于 2013-09-18T04:02:54.067 回答