Python 导入X和从X导入之间有什么区别*
给出的常见解释(如和)是来自X导入的Python 导入X和从X导入之间有什么区别*,python,python-3.x,Python,Python 3.x,给出的常见解释(如和)是来自X导入的* 使名称空间混乱,因此不建议使用。但是,下面的示例 这表明它不仅仅是混乱了名称空间 考虑以下代码: x1.py: g_c = 5 class TestClass(): def run(self): global g_c g_c = 1 print(g_c) # prints 1 x2.py: from x1 import * t = TestClass() t.run() print(g_c) # p
*
使名称空间混乱,因此不建议使用。但是,下面的示例
这表明它不仅仅是混乱了名称空间
考虑以下代码:
x1.py:
g_c = 5
class TestClass():
def run(self):
global g_c
g_c = 1
print(g_c) # prints 1
x2.py:
from x1 import *
t = TestClass()
t.run()
print(g_c) # prints 5, why?
x3.py:
import x1
t = x1.TestClass()
t.run()
print(x1.g_c) # prints 1
运行x2.py
和x3.py
的结果是不同的(在python 3.6.8上)。有人能解释一下原因吗
这两个导入的行为不同
额外注释:(演示@tdelaney提到的关于列表的注释)
更改x1.py中的赋值,如下所示:
g_c = [5]
...
g_c.append(1)
from suman import *
print(display_name())
现在,x2.py和x3.py给出了相同的答案。只有在使用原子类型时才会出现问题。当您导入X时,您必须使用
X
调用X
中的函数,即:
X.func1()
但是,当您使用X import*中的时,您将导入模块命名空间中所有不以\uu
开头的名称或模块中的所有名称,并且您不需要使用X
来调用函数,即:
func1()
在x2.py
中执行以下操作时:
from x1 import *
import x1
t = x1.TestClass()
t.run()
您刚刚从x1
导入了所有内容,包括变量。这意味着您更改了当前脚本的命名空间(x2
)。所以当你打电话时:
print(g_c)
它打印:
5
它是从当前脚本命名空间调用的。
在运行x2
中的类TestClass()
时,它更改了x1
中g_c的值,但没有更改x2
中的值
这表明了使用全局变量的缺点。
当变量被声明为全局变量时,它们将保留在内存中,直到程序执行完成。也就是说,您的全局声明仅在x1
内有效。该声明在x1
的命名空间中有效
当你这么做的时候:
from x1 import *
import x1
t = x1.TestClass()
t.run()
此导入x1
作为一个模块,除非调用它,否则不会导入内部的所有内容。您确实调用了类TestClass()
,并运行了它,结果是类内部的g_c
成为一个全局变量。因此,对于x1
,g_c
是1
,因为它是全局定义的,并且当前脚本不知道x1
有一个g_c=5
,因为它没有导入/调用。
在print(x1.g_c)
上,它在x1的命名空间中调用g_c的值,即1
让我们举一个例子,您将在Python中导入模块suman。它将整个模块带到您的工作区中,即在import suman
语句中,它不允许您访问与like相关的任何方法或函数,例如,如果它们是suman模块中的函数display\u name()
,则您必须像suman.display\u name()
在from suman import*
中,它将suman模块内的所有名称(例如display()
等)带到您的模块中。现在,您可以访问这些名称,而无需模块名称前缀,如下所示:
g_c = [5]
...
g_c.append(1)
from suman import *
print(display_name())
from X import*
将X的全局命名空间中的对象重新绑定到当前模块的命名空间。如果重新分配了其中一个变量,则重新分配对当前命名空间是私有的
不过,导入不会更改导入的对象,它只是添加了一个新引用。例如,classtestclass
的全局名称空间仍然是x1.py
模块TestClass.run
始终更改x1.g_c
(其全局命名空间),无论哪个模块调用它
在x2.py中,将x1.g_c
引用的原始5
导入x2.g_c
。但是重新分配x1.g_c
不会影响x2.g_c
,它是另一个命名空间中的变量
相反地,假设x1.g_c
是一个列表,并且您的代码附加到该列表中。在这种情况下,所有模块都会看到附录,因为您正在修改由x1.g_c
引用的对象,而不是重新分配它。您可以想象从x1 import*
执行的操作与
import m1
globals.update(m1.__dict__)
del m1
换句话说,它导入模块,然后将所有全局变量复制到您的命名空间中。但是,模块中的函数和类将继续引用它们的原始全局变量,而不是命名空间中的副本
注意上面的“实现”并不是完全正确的,因为并不是所有的名称都被复制,还有其他一些微妙之处,但我认为这是理解一般行为的一种简单方法
当模块更改其全局名称空间,但您看不到全局名称空间中反映的更改时,差异就变得明显
从x1导入执行后*
变量sys.modules[“x1”].g_c
和g_c
是两个具有相同值的不同变量;模块中的代码指的是模块内部的代码,而不是您的副本。此行为的关键如下:
Python为每个文件创建名称空间
global X
使变量X
引用位于声明global X
的命名空间中的对象
当在x2.py中执行t.run()
时,将计算global g_c
,这使得g_c
引用名称空间中x1.py而不是x2.py的对象
尝试以下代码片段会有所帮助
x2_uuy.py
from x1 import *
t = TestClass()
t.run()
print(g_c) # prints 5
import x1
print(x1.g_c) # this print 1
因为带星号的导入将分配给模块中的新变量,这些变量将导入到模块中。他们做两件不同的事情,他们的行为并没有什么不同。您可以将带星号的导入和来自模块导入的看作导入模块的糖;some_var=module.some_var;del模块
对我来说,原因是