我试图通过查看流行库中的代码来了解有关Python的更多信息。我修改过的第一个图书馆是Kenneth Reitz的python-requests
。
我所做的只是git clone <request_repo_url_from_github>
,现在我正在检查代码。
我正在查看__init__.py
中的requests/packages
文件。
我有几个问题要问:
为什么__init__.py
内requests/packages
,如果__init__.py
文件下没有requests
文件?或者它是否很简单,因为这是一个直接克隆和卸载的github包,就像这样?
第二个问题参考下面的代码。我想知道的是NullHandler
到底做了什么?我看了一下文档here,有一个'no-op'处理程序意味着什么。这个处理程序将由库开发人员使用在哪里?我的意思是,它有什么特别之处?
import logging
try: # Python 2.7+
from logging import NullHandler
except ImportError:
class NullHandler(logging.Handler):
def emit(self, record):
pass
答案 0 :(得分:3)
根据我对requests
的记忆,packages
目录包含其他依赖项的镜像,作者决定将其与requests
捆绑在一起,而不是添加为依赖项。就个人而言,如果有必要,我会简单地将它们作为依赖项,引用特定版本,但我确信它们有捆绑方法的原因。无论如何,它包含__init__.py
,因此代码可以将其视为一个模块并执行以下操作:
import requests.packages.urllib3
如果查看requests
directory on Github,您会发现该目录中确实存在__init__.py
。如果你想拥有一个包的层次结构,你需要在每个级别都有这样一个文件,尽管在最简单的情况下它可以是一个空文件。
如果你没有将__init__.py
放在一个目录中,Python就不会将它识别为一个包 - 这是为了防止意外包含你不喜欢的地方的模块。您可以想象一下目录可以在sys.path
上的其他地方命名与包相同的任何方式,并导致无法形容的混淆,但由于其中不会有__init__.py
,它会被Python忽略。
要回答第二个问题,NullHandler
适用于出于某种原因方便拥有日志处理程序的情况,但实际上并不想进行任何日志记录。如果你使用的是一个执行日志记录的库,你可能会使用它,但在你的情况下,你实际上并不想记录任何东西 - 你安装一个NullHandler
来抛弃那些记录消息,因为它更容易(和更好的做法)而不是更改他们的库以去除日志记录代码。
在该示例中,我假设您可以添加备用日志记录并简单地设置日志记录级别,以便不会实际生成任何消息,但可以更容易地使用NullHandler
代替。
答案 1 :(得分:1)
在目录中有一个__init__.py
文件会将该目录转换为Python包。它不也将子目录转换为包。如果您查看源树,您会看到它看起来像这样(删除了非相关文件)
requests/
|
|-- __init__.py
|-- packages/
|
|-- __init__.py
|-- charade/
| |
| |-- __init__.py
|-- urllib3/
|
|-- __init__.py
这定义了一个顶级包requests
,以及子包requests.packages
,requests.packages.charade
和requests.packages.urllib3
。定义这些包是必要的,以使它们可以正确导入。
要直接回答您提出的问题, 直接在__init__.py
下 requests/
文件。整棵树中不止一个。
NullHandler
什么也没做。这样就可以无条件地使用logging
库的调用,即使用户没有配置任何记录器也是如此。基本上,当urllib3
尝试记录任何内容时,会调用附加到日志记录库的所有记录器。如果连接了 no 记录器,则日志记录库会发出警告。这些都是糟糕的,所以这是一种解决方法,可以使库代码更简单,而不必强制登录人员。