从命令行运行 Python 时导入 urllib.parse 失败 [英] import urllib.parse fails when Python run from command line
问题描述
我在 python 3.4.2 中观察到以下行为,我无法解释.希望有人能对此事有所了解:
I have observed the following behavior in python 3.4.2, and I am unableto explain it. Hopefully someone could shed some light on the matter:
在 IPython 中:
In IPython:
In [129]: import urllib
In [130]: print(urllib.parse)
<module 'urllib.parse' from '/Users/ashwin/.pyenv/versions/3.4.2/lib/python3.4/urllib/parse.py'>
我已经导入了一个模块,并打印了它的一个属性.一切都按预期工作.到目前为止,生活还不错.
I've imported a module, and printed one of its attributes. Everything works as expected. So far, life is good.
现在,我从命令行做同样的事情:
Now, I do the same thing from the command line:
$ python -c 'import urllib; print(urllib.parse)'
Traceback (most recent call last):
File "<string>", line 1, in <module>
AttributeError: 'module' object has no attribute 'parse'
说什么?!这不是应该的工作方式.
好吧,也许这是一个 python 范围的行为;使用 -c
标志时,可能不会立即导入模块.让我们尝试另一个模块:
Say what?! that's not how that's supposed to work.
Ok, maybe this is a python-wide behavior; maybe modules are not immediately imported when using the -c
flag. Let's try another module:
$ python -c 'import datetime; print(datetime.datetime)'
<class 'datetime.datetime'>
什么?!它如何适用于 datetime
而不适用于 urllib
?我在两个地方都使用相同版本的 python (3.4.2)
What?! How does it work for datetime
and not for urllib
? I'm using the same version of python in both places (3.4.2)
有人对此有任何想法吗?
Does anyone have any thoughts on this?
编辑:
每一条评论:
$ which -a ipython
/Users/ashwin/.pyenv/shims/ipython
/Library/Frameworks/Python.framework/Versions/2.7/bin/ipython
/usr/local/bin/ipython
/usr/local/bin/ipython
和
$ which -a python
/Users/ashwin/.pyenv/shims/python
/Library/Frameworks/Python.framework/Versions/2.7/bin/python
/usr/bin/python
/usr/bin/python
推荐答案
当您运行 import urllib
时,它会创建 urllib
模块的模块对象(实际上是一个 package) 无需导入它的子模块(解析、请求等).
When you run import urllib
, it creates the module object of the urllib
module (which is actually a package) without importing its submodules (parse, request etc.).
如果您想使用属性访问访问其子模块,您需要父模块对象 (urllib
) 位于您的命名空间中.除此之外,该子模块必须已经加载(导入).来自文档:
You need the parent module object (urllib
) to be in your namespace if you want to access its submodule using attribute access. In addition to that, that submodule must already be loaded (imported). From the documentation:
如果包spam
有子模块foo
,导入后spam.foo
, spam
将有一个属性 foo
绑定到子模块.[...] 不变的持有是,如果你有sys.modules['spam']
和 sys.modules['spam.foo']
(就像你在上述导入之后),后者必须作为 foo
属性出现前者.
if package
spam
has a submodulefoo
, after importingspam.foo
,spam
will have an attributefoo
which is bound to the submodule. [...] The invariant holding is that if you havesys.modules['spam']
andsys.modules['spam.foo']
(as you would after the above import), the latter must appear as thefoo
attribute of the former.
每个模块只有一个实例,因此对 urllib
模块对象(存储在 sys.modules['urllib']
中)所做的任何更改都会在任何地方反映出来.
There is only one instance of each module, thus any changes made to the urllib
module object (stored in sys.modules['urllib']
) get reflected everywhere.
您不导入 urllib.parse
,但 IPython 会. 为了证明这一点,我将创建一个启动文件:
You don't import urllib.parse
, but IPython does. To prove this I'm going to create a startup file:
import urllib
print('Running the startup file: ', end='')
try:
# After importing 'urllib.parse' ANYWHERE,
# 'urllib' will have the 'parse' attribute.
# You could also do "import sys; sys.modules['urllib'].parse"
urllib.parse
except AttributeError:
print("urllib.parse hasn't been imported yet")
else:
print('urllib.parse has already been imported')
print('Exiting the startup file.')
并启动 ipython
vaultah@base:~$ ipython
Running urllib/parse.py
Running the startup file: urllib.parse has already been imported
Exiting the startup file.
Python 3.6.0a0 (default:089146b8ccc6, Sep 25 2015, 14:16:56)
Type "copyright", "credits" or "license" for more information.
IPython 4.0.0 -- An enhanced Interactive Python.
是IPython启动时导入pydoc
的副作用(which ipython
是/usr/local/bin/ipython):
It is the side effect of importing pydoc
during the startup of IPython (which ipython
is /usr/local/bin/ipython):
/usr/local/bin/ipython, line 7:
from IPython import start_ipython
/usr/local/lib/python3.6/site-packages/IPython/__init__.py, line 47:
from .core.application import Application
/usr/local/lib/python3.6/site-packages/IPython/core/application.py, line 24:
from IPython.core import release, crashhandler
/usr/local/lib/python3.6/site-packages/IPython/core/crashhandler.py, line 28:
from IPython.core import ultratb
/usr/local/lib/python3.6/site-packages/IPython/core/ultratb.py, line 90:
import pydoc
/usr/local/lib/python3.6/pydoc.py, line 68:
import urllib.parse
这解释了为什么下面的代码失败 - 你只导入 urllib
而似乎没有导入 urllib.parse
:
This explains why the below code fails - you only import urllib
and nothing seems to import urllib.parse
:
$ python -c 'import urllib; print(urllib.parse)'
另一方面,以下命令有效,因为datetime.datetime
不是一个模块.这是一个在 import datetime
期间导入的类.
On the other hand, the following command works because datetime.datetime
is not a module. It's a class that gets imported during import datetime
.
$ python -c 'import datetime; print(datetime.datetime)'
这篇关于从命令行运行 Python 时导入 urllib.parse 失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!