>>> 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进行了更改,则更改将保留在模块中,以便每次再次导入时,都是修改后的版本。
真实问题:
import
以这种方式实施?为什么不让每个import math
导入一个新的,未经修改的math
副本?为什么要导入导入的math
? math.pi
后,是否有任何解决方法可以让math.pi = 3
回来(当然除了math.pi = 3.141592653589793
)? import math
比from math import *
更受欢迎。但是这种行为让我担心如果我这样做,其他人可能会修改我导入的模块......我应该怎样做import
?答案 0 :(得分:13)
Python只创建任何给定模块的一个副本。重复导入模块会重复使用原始模块。这是因为如果模块A和B导入C和D,导入E和F等,C和D将被加载两次,E和F将被加载4次,等等。除了最琐碎的依赖之外图表,你会花费几分钟加载冗余模块,然后内存不足。另外,如果A导入的B和B导入了A,那么你会陷入一个递归循环,而且内存不足而没有做任何有用的事情。
解决方案:不要使用其他模块的内容。如果这样做,那就是解释器范围内的更改。有时候你会想要这样做,所以Python会让你,但这通常是一个坏主意。
答案 1 :(得分:10)
可以多次导入模块。 import
语句只会从sys.modules
加载引用。如果import
语句也从磁盘重新加载模块,那么它将非常慢。修改这样的模块是非常不寻常的,只能在罕见的记录情况下完成,因此无需担心。
如何reload模块:
>>> import imp
>>> imp.reload(math)
<module 'math' (built-in)>
>>> math.pi
3.141592653589793
答案 2 :(得分:6)
导入行为旨在允许模块具有状态。例如,运行初始化代码的模块可能具有基于初始化时发生的各种不同行为(一个很好的例子是os模块,它根据你所使用的操作系统透明地加载不同版本的路径子模块) 。通常的行为是允许许多不同的代码访问模块而不重复运行初始化。此外,模块的功能类似于其他语言中的静态类 - 它们可以维护状态,通常用作全局变量的替代:例如,您可以使用语言环境模块来设置本地文化变量(货币格式等) - 调用代码的一部分中的 locale.setlocale 和另一部分中的 local.getlocale 是创建全局变量的一个很好的替代方法。
当然,你的例子指出了这个弱点。其中一个经典的python原则是
我们都是成年人
该语言并未提供您在Java或C#中找到的大部分隐私管理功能,这些功能可让作者锁定模块或类的内容。如果您感觉恶意(或只是自杀),您可以完成您的示例中完成的那种事情:将pi更改为等于3,或将函数转换为变量或各种其他令人讨厌的东西。这种语言并不是为了使这种语言难以实现 - 编码员需要负责。