在某些系统上使用urllib
加载幻像模块时,似乎会出现一些意外行为。行为如下:
Python 3.5.2 (default, Aug 18 2017, 17:48:00)
[GCC 5.4.0 20160609] 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.foo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'urllib' has no attribute 'foo'
>>> dir(urllib)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'error', 'parse', 'request', 'response']
意外行为是仅在尝试访问错误属性并获取AttributeError
后才加载其他名称。在具有相同python解释器的另一个系统(Ubuntu 16.04 apt python3
)上,这不会发生:
Python 3.5.2 (default, Nov 17 2016, 17:05:23)
[GCC 5.4.0 20160609] on linux
>>> import urllib
>>> dir(urllib)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__']
>>> urllib.foo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'urllib' has no attribute 'foo'
>>> dir(urllib)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__']
我们已经在几个操作系统和解释器上进行了测试,并且唯一表现出意外行为的是从apt
获得的Ubuntu 14.04 Python 3.4.0。在这个系统上,我们还验证了当出现完全不相关的异常时,它似乎也会发生......
Python 3.4.0 (default, Apr 11 2014, 13:05:18)
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> raise Exception('uh oh')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Exception: uh oh
>>> import urllib
>>> dir(urllib)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'error', 'parse', 'request', 'response']
这里发生了什么?
答案 0 :(得分:4)
您安装了Apport,这是Ubuntu用来捕获软件崩溃的软件包。
该软件包包含一个安装sys.excepthook
function的Python软件包;只要在Python程序中引发未处理的异常,就会调用此挂接。该钩子的实现间接加载urllib.*
个模块。
通过触发交互式解释器中的异常,您触发了钩子,导致额外的Python代码运行,从而添加了导入。
见apport_python_hook.py
source code;调用钩子时,会加载各种apport
模块,包括导入urllib
模块的apport.report
。
您可以通过在enabled = 0
中设置/etc/default/apport
来停用此功能。
将来,如果您想要查看导入,可以使用-v
command-line switch运行Python或设置PYTHONVERBOSE
environment variable;当你打开Python时,已经告诉你apport_python_hook
模块被加载了,并且在引发异常时加载了更多的模块。