在python 3.5.x中使用`urllib`加载意外的模块

时间:2017-09-29 20:30:17

标签: python python-3.x urllib

在某些系统上使用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']

这里发生了什么?

1 个答案:

答案 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模块被加载了,并且在引发异常时加载了更多的模块。