我import module
和from module import name1, name2 ...
Python之间的区别有问题。我是Python的新手(上周),在Windows-64上使用Python 3.6。
在Python教程中,对这两种import
方法进行了简短的讨论。声明from module import *
不建议这样做,因为有污染当前名称空间的危险。但是,没有迹象表明import module
和之间存在任何实质性的操作差异from module import name1, name2..
,这暗示着这是优先考虑或方便的问题。
但是,实践似乎有很大的不同。考虑这个名为ModuleA的模块,它定义了一个全局变量和一个函数:
# ModuleA
iGlobalA = 0
def fA():
iGlobalA += 1
print( "MA: iGlobalA=", iGlobalA )
print( "Module A Initialised, iGlobalA=", iGlobalA )
使用import ModuleA
创建一个单独的ModuleA
名称空间。现在,该模块的成员可用作名称空间的公共成员,如下所示:
import ModuleA as MA
def fX():
print( "MX: Before, ModuleA.iGlobalA=", MA.iGlobalA )
MA.fA()
print( "MX: After 1, ModuleA.iGlobalA=", MA.iGlobalA )
MA.fA()
print( "MX: After 2, ModuleA.iGlobalA=", MA.iGlobalA )
fX()
这是输出:
MA: Initialised, iGlobalA= 100
MX: Before, ModuleA.iGlobalA= 100
MA: iGlobalA incremented to 101
MX: After 1, ModuleA.iGlobalA= 101
MA: iGlobalA incremented to 102
MX: After 2, ModuleA.iGlobalA= 102
完全符合预期。将此与使用该格式的ModuleY进行对比from ModuleA import fA, iGlobalA
,然后无条件地引用ModuleA的这些成员:
# ModuleY
from ModuleA import fA, iGlobalA
def fY():
print( "MY: Before, ModuleA.iGlobalA=", iGlobalA )
fA()
print( "MY: After 1, ModuleA.iGlobalA=", iGlobalA )
fA()
print( "MY: After 2, ModuleA.iGlobalA=", iGlobalA )
fY()
在这种情况下,输出为:
MA: Initialised, iGlobalA= 100
MY: Before, ModuleA.iGlobalA= 100
MA: iGlobalA incremented to 101
MY: After 1, ModuleA.iGlobalA= 100
MA: iGlobalA incremented to 102
MY: After 2, ModuleA.iGlobalA= 100
在这种情况下,在初始化ModuleA之后,全局变量作为副本从ModuleAiGlobalA
导入,并成为与完全独立的变量。确实,导入功能是在导入时定义的,作为对ModuleA中功能的引用-如果稍后在ModuleA中重新分配该功能,则导入模块中对的引用保持不变,仅指向最初导入的功能。ModuleA.iGlobalA
fA
fA()
我本以为应该在文档中更清楚地说明这些导入语法之间的这些差异。这也意味着设计库模块的人需要指定如何导入该模块。
编辑-@ abdullah-ahmed-ghaznavi发表评论后,这是我的问题
在这种情况下,全局变量iGlobalA作为副本从ModuleA导入。
不。刚过from ModuleA import iGlobalA
,双方ModuleA.iGlobalA
并ModuleY.iGlobalA
指向相同的对象-您可以通过打印检查这id(iGlobalA)
两个模块。现在,虽然两个名称(最初)都指向同一个对象,但名称本身却是不同的-它们位于不同的命名空间中(一个在另一个名称空间ModuleA
中ModuleY
),因此,当fA()
重新绑定该名称时iGlobalA
-实际上ModuleA.iGlobalA
-仅ModuleA
会影响进入该名称的名称(因此,此时两个名称都指向不同的对象)。
另一方面,当ModuleY
您使用限定名称时ModuleA.iGlobalA
,您只有一个名称,因此当该名称反弹时ModuleA
,fA()
您会看到的变化ModuleY
,因为您实际上是在检查相同的名称。
请注意,如果您不想更改名称而不是尝试使用相同的方法来更改可变对象(即,追加到列表,更新字典等),则不会注意到行为上的任何区别:
# ModuleA
iGlobalA = []
def fA():
iGlobalA.append(1)
print( "MA: iGlobalA=", iGlobalA )
print( "Module A Initialised, iGlobalA=", iGlobalA )
您在这里需要了解的主要是Python“变量”的真正含义,并且Python没有真正的全局名称空间(“ global”实际上意味着“模块级别”)。
我本以为应该在文档中更清楚地说明这些导入语法之间的这些差异。
可能是的。请注意,实际上有一些关于整件事的文档,请参阅https://docs.python.org/3/reference/simple_stmts.html#import和https://docs.python.org/3/reference/import.html,但实际上您确实必须了解“在本地名称空间中定义名称”和“对该值的引用存储在本地名称空间中”的含义。
这也意味着设计库模块的人需要指定如何导入该模块。
这里的问题是,要么下的lib设计很糟糕(如果它使用全局变量这样,它是非常确实的设计)的lib的API或(至少),您尝试访问的名称不(或不应该)部分。
我错过了文档中的某些内容吗?
恐怕也是,我恐怕已经太习惯这种工作方式了,以至于我还记得我第一次学习它的方法。
所有平台上的行为都一样吗?这是将来可以依赖的预期行为吗?
是的,是的。实际上,这是该语言规范的一部分,对其进行更改将破坏几乎所有现有代码。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句