默认情况下,你不能在python3.9中导入urllib中的模块。
python3
Python 3.9.6 (default, Jul 14 2021, 09:15:03)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import urllib
>>> dir(urllib)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__']
让我们检查一下urllib中是哪个模块
ls /usr/local/lib/python3.9/urllib/
error.py parse.py request.py robotparser.py
__init__.py __pycache__ response.py
cat /usr/local/lib/python3.9/urllib/__init__.py
#it contains blank line.
>>> import urllib
>>> web = urllib.request.urlopen('https://www.yahoo.com')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'urllib' has no attribute 'request'
最佳实践是import urllib.request
在许多在线教程中建议。
默认情况下,__init__.py
为空,不包含任何内容。所以必须写import urllib.request
来导入它,现在我在/usr/local/lib/python3.9/urllib/__init__.py
中添加以下行。
from . import error
from . import parse
from . import request
from . import robotparser
from . import response
然后打开网页:
>>> import urllib
>>> web = urllib.request.urlopen('https://www.yahoo.com')
>>> web.info
<bound method HTTPResponse.info of <http.client.HTTPResponse object at 0x7f2654757430>>
为什么作者不添加/usr/local/lib/python3.9/urllib/__init__.py
中的行?
查看Python 3源代码中的Git历史记录,对于cpython/Lib/urllib/__init__.py
,我发现了一个单独的提交:
生成一个新的urllib包。它由来自urllib、urllib2、urlparse和robotparser的代码组成。旧模块已全部移除。新包有五个子模块:urllib。urllib解析。请求、urllib.responseurllib。Error和urllib. roboparser。urllib.request.urlopen()函数使用urllib2中的url打开器。
然后查看Python 2的源代码历史,似乎这四个库最初都是以平面文件的形式存在的。
所以我的最好的猜测是,在从Python 2到3的过渡期间,将一些相关的库组合在一起,他们认为这个子模块结构将是最容易理解和维护的。通过__init__.py
文件强制解决这个问题可能是为了减轻最终用户对方法血统的一些困惑:也就是说,哪些函数最初来自哪个Python 2库。从本质上讲,用顶级导入的边际便利换取更好的模块化和从用户的角度更清晰地分离关注点。