Python中导入模块与from模块导入之间的区别的问题

约翰·RC

import modulefrom 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.iGlobalAfAfA()

我本以为应该在文档中更清楚地说明这些导入语法之间的这些差异。这也意味着设计库模块的人需要指定如何导入该模块。

编辑-@ abdullah-ahmed-ghaznavi发表评论后,这是我的问题

  • 我错过了文档中的某些内容吗?
  • 所有平台上的行为都一样吗?
  • 这是将来可以依赖的预期行为吗?
布鲁诺·德舒利耶

在这种情况下,全局变量iGlobalA作为副本从ModuleA导入。

不。刚过from ModuleA import iGlobalA,双方ModuleA.iGlobalAModuleY.iGlobalA指向相同的对象-您可以通过打印检查这id(iGlobalA)两个模块。现在,虽然两个名称(最初)都指向同一个对象,但名称本身却是不同的-它们位于不同的命名空间中(一个在另一个名称空间ModuleAModuleY),因此,当fA()重新绑定该名称时iGlobalA-实际上ModuleA.iGlobalA-仅ModuleA会影响进入该名称的名称(因此,此时两个名称都指向不同的对象)。

另一方面,当ModuleY您使用限定名称时ModuleA.iGlobalA,您只有一个名称,因此当该名称反弹时ModuleAfA()您会看到的变化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#importhttps://docs.python.org/3/reference/import.html,但实际上您确实必须了解“在本地名称空间中定义名称”和“对该值的引用存储在本地名称空间中”的含义。

这也意味着设计库模块的人需要指定如何导入该模块。

这里的问题是,要么下的lib设计很糟糕(如果它使用全局变量这样,它非常确实的设计)的lib的API或(至少),您尝试访问的名称不(或不应该)部分。

我错过了文档中的某些内容吗?

恐怕也是,我恐怕已经太习惯这种工作方式了,以至于我还记得我第一次学习它的方法。

所有平台上的行为都一样吗?这是将来可以依赖的预期行为吗?

是的,是的。实际上,这是该语言规范的一部分,对其进行更改将破坏几乎所有现有代码。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章