在 Python 中导入模块是否会在本地范围内执行模块的所有导入?
Does importing a module in Python execute all the module's imports in local scope?
$ python -c 'import urllib.parse; print(urllib.error.HTTPError)'
Traceback (most recent call last):
File "<string>", line 1, in <module>
AttributeError: module 'urllib' has no attribute 'error'
这是意料之中的。我还没有导入 urllib.error
模块。
$ python -c 'import urllib.request; print(urllib.request.HTTPError)'
<class 'urllib.error.HTTPError'>
这个也是。 urllib.request
imports urllib.error
:
from urllib.error import URLError, HTTPError, ContentTooShortError
因此可以通过 urllib.request
获得名称。
$ python -c 'import urllib.request; print(urllib.error.HTTPError)'
<class 'urllib.error.HTTPError'>
但不是这个。是什么让我能够通过 urllib.error
访问 HTTPError
?我读过 the docs,但没有看到任何线索。
不确定这是否符合您的预期,但这是设计。你看看 urllib/parse.py 和 urllib/request.py 的来源你会发现一个重要的区别:前者只导入 re、sys 和 collections 模块,而后者(除了其他不相关的模块) ) 还明确地从 urllib.error、urllib.parse 和 urllib.response.
导入符号
这就是为什么即使导入不在您自己的源文件中,您也会发现它们可用的原因。
更详细的答案需要对 Python 进口机械进行详细描述,这远远超出了 SO 答案中的适当范围。更深入的解释请参考官方文档
好的,让我们看看:
import urllib.parse
globals()
您将看到一个项目:
'urllib': <module 'urllib' from 'C:\Users\XXXX\AppData\Local\Programs\Python\Python35\lib\urllib\__init__.py'>
然后,尝试dir(urllib)
,你会看到:
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'parse']
所以urllib
中有一个parse
,但没有request
或error
。因为 parse
不导入它们。
现在让我们去urllib.request
:
import urllib.request
globals()
获得一件物品:
'urllib': <module 'urllib' from 'C:\Users\XXXX\AppData\Local\Programs\Python\Python35\lib\urllib\__init__.py'>
与import urllib.parse
相同。
然后再试一次dir(urllib)
:
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'error', 'parse', 'request', 'response']
里面有'error', 'parse', 'request', 'response'
个。为什么? 因为 urllib.request
导入它们。
让我试着更详细地解释一下。导入 urllib.request
首先导入 urllib
,然后是 urllib.request
。导入 urllib
会在局部范围内为我们提供 urllib
符号,表示已导入模块。导入 urllib.request
会导入 urllib.error
等等。它将 error
符号添加到 urllib
模块。并且 因为我们引用了 urllib
,所以我们可以在导入 urllib.request
之后访问 urllib.error
。考虑以下示例:
./main.py
#!/usr/bin/env python
import a.b
print(a.c.c) # 2
print(d.e.e) # NameError
./a/b.py
import a.c
import d.e
b = 1
./a/c.py
c = 2
./d/e.py
:
e = 3
$ python -c 'import urllib.parse; print(urllib.error.HTTPError)'
Traceback (most recent call last):
File "<string>", line 1, in <module>
AttributeError: module 'urllib' has no attribute 'error'
这是意料之中的。我还没有导入 urllib.error
模块。
$ python -c 'import urllib.request; print(urllib.request.HTTPError)'
<class 'urllib.error.HTTPError'>
这个也是。 urllib.request
imports urllib.error
:
from urllib.error import URLError, HTTPError, ContentTooShortError
因此可以通过 urllib.request
获得名称。
$ python -c 'import urllib.request; print(urllib.error.HTTPError)'
<class 'urllib.error.HTTPError'>
但不是这个。是什么让我能够通过 urllib.error
访问 HTTPError
?我读过 the docs,但没有看到任何线索。
不确定这是否符合您的预期,但这是设计。你看看 urllib/parse.py 和 urllib/request.py 的来源你会发现一个重要的区别:前者只导入 re、sys 和 collections 模块,而后者(除了其他不相关的模块) ) 还明确地从 urllib.error、urllib.parse 和 urllib.response.
导入符号这就是为什么即使导入不在您自己的源文件中,您也会发现它们可用的原因。
更详细的答案需要对 Python 进口机械进行详细描述,这远远超出了 SO 答案中的适当范围。更深入的解释请参考官方文档
好的,让我们看看:
import urllib.parse
globals()
您将看到一个项目:
'urllib': <module 'urllib' from 'C:\Users\XXXX\AppData\Local\Programs\Python\Python35\lib\urllib\__init__.py'>
然后,尝试dir(urllib)
,你会看到:
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'parse']
所以urllib
中有一个parse
,但没有request
或error
。因为 parse
不导入它们。
现在让我们去urllib.request
:
import urllib.request
globals()
获得一件物品:
'urllib': <module 'urllib' from 'C:\Users\XXXX\AppData\Local\Programs\Python\Python35\lib\urllib\__init__.py'>
与import urllib.parse
相同。
然后再试一次dir(urllib)
:
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'error', 'parse', 'request', 'response']
里面有'error', 'parse', 'request', 'response'
个。为什么? 因为 urllib.request
导入它们。
让我试着更详细地解释一下。导入 urllib.request
首先导入 urllib
,然后是 urllib.request
。导入 urllib
会在局部范围内为我们提供 urllib
符号,表示已导入模块。导入 urllib.request
会导入 urllib.error
等等。它将 error
符号添加到 urllib
模块。并且 因为我们引用了 urllib
,所以我们可以在导入 urllib.request
之后访问 urllib.error
。考虑以下示例:
./main.py
#!/usr/bin/env python
import a.b
print(a.c.c) # 2
print(d.e.e) # NameError
./a/b.py
import a.c
import d.e
b = 1
./a/c.py
c = 2
./d/e.py
:
e = 3