Python 为什么“中的全局变量的行为不同?”;“导入模块”;vs";从模块导入*“;?

Python 为什么“中的全局变量的行为不同?”;“导入模块”;vs";从模块导入*“;?,python,python-3.x,Python,Python 3.x,让我们来看看a.pybe: def foo(): global spam spam = 42 return 'this' 在控制台上,如果我只是导入一个,事情对我来说是有意义的: >>> import a >>> a.foo() 'this' >>> a.spam 42 然而,如果我做了不太受欢迎的事情 >>> from a import * >>> foo() 'this' &

让我们来看看a.pybe:

def foo():
    global spam
    spam = 42
    return 'this'
在控制台上,如果我只是导入一个,事情对我来说是有意义的:

>>> import a
>>> a.foo()
'this'
>>> a.spam
42
然而,如果我做了不太受欢迎的事情

>>> from a import *
>>> foo()
'this'
>>> spam
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'spam' is not defined
>>> a.spam
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
来自导入的
>>*
>>>foo()
‘这’
>>>垃圾邮件
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
NameError:未定义名称“垃圾邮件”
>>>垃圾邮件
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
NameError:未定义名称“a”

我已经从名称空间的角度阅读了关于为什么人们不喜欢“模块导入中的
*
”的观点,但我找不到关于这种行为的任何信息,坦率地说,我发现这是我偶然遇到的问题。

当你请求
a.spam
时,模块
a
中发生了名称空间搜索,找到了
spam
。但是当你要求垃圾邮件时:

>>> from a import *  # imported foo, spam doesn't exist yet
>>> foo()
spam
是在名称空间a中创建的(但您不能通过此类导入访问它),但不是在当前模块中创建的。而且似乎没有人答应我们将新添加的
a
全局添加到所有名称空间模块
a
已通过
*
导入。这将需要在解释器中存储导入链接,如果一个大量导入的模块一直在使用这种技巧,那么可能会降低性能

想象一下,在调用
foo()
之前,您已经在主模块中定义了
spam
。那将是彻头彻尾的名称冲突

如图所示,您可以从导入中执行
*
,以获取模块
a
的新更新:

from a import *
print(foo())
from a import *
print(spam)

我大体上同意Vovanrock2002

正如最近向我解释的,“.”是范围解析操作符<代码>导入和导入中的提供不同的语法<代码>从导入*分别从
a
导入每个全局变量,并将它们作为局部范围内的变量绑定。一个更实际的例子可能是
import datetime
from datetime import date
之间的差异。对于前者,我必须使用
datetime.date(2015,11,12)
创建一个日期对象,对于后者,我只能使用
date(2015,11,12)

你可以在网上阅读更多


不过,我不同意你的看法,因为我不相信垃圾邮件是生命、宇宙和一切的意义。

让我们一步一步地深入了解它:

在导入时,
a
仅具有表示函数的符号
foo

只有在执行该函数时,
a
才会获取附加符号
spam

在第一种情况下,您导入一个,并获得模块的“句柄”,这允许您监视以后发生的任何事情。如果在调用
a.foo()
之前执行
a.spam
,则会出现错误


在第二种情况下,导入中的
将为您提供模块中当前的任何内容,这就是
spam()
。调用该函数后,您可以从导入中执行
*
,以获得
垃圾邮件

a.py
中定义的全局变量在该模块本身中是全局变量,因此它不会在您导入它的地方定义全局变量。检查
foo.\uuuuu globals\uuuuuuu
。这足够清楚,我可以理解,谢谢。在第二种情况下,调用spam或a.spam不起作用。我也同意,如果垃圾邮件真的是答案,世界将是一个悲哀的地方。