$ 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
导入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
?我已经阅读了文档,但那里没有线索。
好吧,让我们看看:
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
不确定是否是您预期的,但这是设计的。您是否查看urllib/parse.py和urllib/request的来源。来自urllib.error,urllib.parse和urllib.Response的符号。
这就是为什么即使导入不在您自己的源文件中,也可以找到可用的原因。
一个更详细的答案将需要对Python导入机械进行详细说明,并且远远超出了SO答案中的适当情况。请参阅官方文件以进行更深入的解释。