我正在使用Python 3.3,在Windows上测试它。我不明白。我为什么这样做:
>>> import urllib
我收到错误
>>> urllib.request
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'request'
和
>>> dir(urllib)
['__builtins__', '__cached__', '__doc__', '__file__', '__initializing__',
'__loader__', '__name__', '__package__', '__path__']
没有请求,所以看起来很稳固。但是在导入子模块请求时:
>>> import urllib.request
似乎有效
>>> urllib.request
<module 'urllib.request' from 'C:\\Python33\\lib\\urllib\\request.py'>
现在自动dir(urllib)
显示:
>>> dir(urllib)
['__builtins__', '__cached__', '__doc__', '__file__', '__initializing__',
'__loader__', '__name__', '__package__', '__path__', 'error', 'parse',
'request', 'response']
为什么我看不到所有子模块import urllib
之后?根据{{3}},它应该是request
,error
,parse
,parserobots
。它在其他操作系统中有所不同吗?
答案 0 :(得分:2)
当你
时>>> import package
>>> package.something
您真正在做的是寻找something
中定义的名称package/__init__.py
。因此,如果某人明确地在那里放了一些名字,你可以使用它否则你就不能。
例如,查看Python web.py
库(github)。你可以
>>> import web # which is a package
>>> web.httpserver # which is a module located in web/httpserver.py
<module 'web.httpserver' ...>
它在这里,因为在web/__init__.py
中有明确的import httpserver
或类似声明。
实际上它不是Python 3的问题。你在Python 3中遇到它,因为它使用标准库的包而不仅仅是像Python 2那样的普通模块。urllib/__init__.py
由于某种原因而currently empty因此你需要明确地import
精确的模块像request
一样使用它们。对于一些标准软件包Python 3 import
一些&#34;子模块&#34;在相应的__init__.py
个文件中。也许它只是为了向后兼容。
另一个问题是为什么在import urllib.request
dir(urllib)
之后,response
显示其他模块,例如urllib.request
。看起来import
在import urllib.error
内部使用的同一包中的所有模块都可用。如果您request
error
,则sys.modules
不会使用它{{1}}。如果你检查Python导入系统的源代码,这一切都变得更容易理解 - 它充满了副作用(例如&#34;缓存&#34;使用全局{{1}}字典导入的模块)。
答案 1 :(得分:0)
urllib
是一个包。导入包不会自动导入包中包含的模块;您需要显式导入urllib.request
模块。
答案 2 :(得分:0)
让我们看看dir()
。如文档中所述,它列出了模块中定义的名称 - 而packages模块是__init__.py
。 request
urllib
中未定义__init__
,因此不会列出。
现在,对于“包如何工作” - 包是某种基于目录的模块。它从__init__.py
加载,但允许子模块和子包(与__init__
在同一目录中的文件和目录)。现在,当您加载包(例如urllib
)时,您不会加载(“加载”意味着“执行其代码”)其中的所有文件和目录,但只有它是“初始化程序”(想想{{1} }作为类的__init__.py
方法,但对于模块 - 在最后模块和类都是对象,对吗?)。
与类的比较非常好 - 当你创建对象时,你只调用它的__init__
方法,而不是它的所有属性(方法也是属性)。此外,属性可以是函数或字段。字段也可以具有属性。澄清:
__init__
适用于__init__.py
对象的包
子模块用于包对象的哪个方法(函数属性)
子包用于包对象的哪个字段(非函数属性)。
为什么呢? __init__
负责设置对象,子模块/方法是在一个地方存储逻辑的方法,子包/字段是组织其他子模块/方法或子子包/字段的方式。
坦率地说:它在CPython实现中不会像这样工作,但它是理解它将如何表现的非常好的模型。