从...导入与导入.的区别

369

我想知道下面代码片段之间是否有区别:

from urllib import request

和片段

import urllib.request

或者它们是否可以互换使用?如果可以互换,哪种是“标准”/“首选”语法(如果有的话)?


1
жҲ‘дёҚжҳҜimportж–№йқўзҡ„专家пјҢжүҖд»ҘжҲ‘дёҚдјҡз•ҷдёӢзӯ”жЎҲпјҢдҪҶжҳҜе…ідәҺеҰӮдҪ•иҝӣе…Ҙsys.modulesзҡ„ж–№ејҸжңүжүҖдёҚеҗҢпјҡиҜ·зңӢдёҖдёӢиҝҷдёӘзӯ”жЎҲпјҲеңЁжң«е°ҫпјүгҖӮ*(д№ҹи®ёжңүдәәжҜ”жҲ‘жӣҙеҘҪең°и§ЈйҮҠ)* - Rik Poggi
6个回答

319

这取决于您希望在引用时如何访问该导入项。

from urllib import request
# access request directly.
mine = request()

import urllib.request
# used as urllib.request
mine = urllib.request()

当您导入某些内容时,为了简便或避免掩盖内置内容,您也可以自己创建别名:

from os import open as open_
# lets you use os.open without destroying the 
# built in open() which returns file handles.

4
我刚刚尝试导入urllib.request,但它完全不起作用(Python 2.6.5 Ubuntu)。 - tkone
9
为避免与内置函数冲突,应该使用下划线后缀而不是前缀。 - deadly
@deadly - 不好的习惯 - 有时在Eclipse中使用前导下划线会防止IDE警告。谢谢。 - g.d.d.c
27
“单个下划线后缀”的约定在PEP 8中明确规定了两次。如果Eclipse对正确代码生成烦人的警告,那么我们有一个不好的IDE,而不是一个不好的习惯。 - wchargin
1
@tkone 在 Python 3 中,urllib2 被移动到 urllib.request。 - Arcanum

249

许多人已经解释了importfrom的区别,因此我想尝试更深入地解释一下它们之间的实际区别。

首先,让我解释一下基本的导入语句都做了什么。

import X

导入模块X并在当前命名空间中创建对该模块的引用。然后需要定义完成的模块路径来从模块内部访问特定属性或方法(例如:X.nameX.attribute)。

from X import *

导入模块X并在当前命名空间中创建对该模块定义的所有公共对象的引用(即除了以_开头的名称之外的所有内容)或者您指定的名称。

换句话说,在运行此语句之后,您只需使用简单的(未经限定的)名称即可引用模块X中定义的内容。但是,并没有定义X本身,所以X.name不能工作。如果name已经定义,则被新版本取代。如果X中的name被更改以指向其他对象,则您的模块不会注意到。

这使得模块中的所有名称都在本地命名空间中可用。

现在让我们看看当我们执行import X.Y时会发生什么:

>>> import sys
>>> import os.path

检查名称为osos.pathsys.modules

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

使用名称 os os.path 检查 globals() locals() 命名空间字典:

 >>> globals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> locals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> globals()['os.path']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os.path'
>>>    

从上面的例子中,我们发现只有os被添加到了本地和全局命名空间中。 因此,我们应该能够使用os

 >>> os
 <module 'os' from     
  '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
 >>> os.path
 <module 'posixpath' from      
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
 >>>

...但不包括path

>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined 
>>>

如果你从locals()命名空间中删除了os,那么即使osos.pathsys.modules中存在,你也将无法访问它们:

>>> del locals()['os']
>>> os
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

现在让我们来看一下from

from

>>> import sys
>>> from os import path

检查名为 osos.pathsys.modules

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

因此,sys.modules在使用import name导入时与之前一样。

好的。让我们检查一下locals()globals()命名空间字典的情况:

>>> globals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> locals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['os']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os'
>>>

您可以使用path来访问,但不能使用os.path

>>> path
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>
 

让我们从locals()中删除'path':

>>> del locals()['path']
>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

最后一个关于别名的例子:

>>> from os import path as HELL_BOY
>>> locals()['HELL_BOY']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['HELL_BOY']
<module 'posixpath' from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>>

没有定义路径:

>>> globals()['path']
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
KeyError: 'path'
>>>

使用from时需要注意的一个陷阱

如果你从两个不同的模块中导入了相同的 name

>>> import sys
>>> from os import stat
>>> locals()['stat']
<built-in function stat>
>>>
>>> stat
<built-in function stat>

再次从shutil导入stat

>>>
>>> from shutil import stat
>>> locals()['stat']
<module 'stat' from 
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/stat.pyc'>
>>> stat
<module 'stat' from 
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/stat.pyc'>
>>>

最后导入的内容将会覆盖之前的同名内容


8
确实是这样,但对我来说,所有这些命名空间等都有点令人困惑。因此我更喜欢只使用import x,然后是x.what_is_necessary。在我看来,这样更易读和易于避免混淆。通过这种方式,您可以确保避免名称冲突、歧义以及各种其他问题……对吧? - udarH3
21
我喜欢这个答案,因为它教会了人们如何捕鱼而不是提供鱼。 - Dana
4
from . import <classyouwant> 是 Python 中的一种导入方式,它表示从当前模块中导入指定的类。其中的点 . 表示当前模块所在的包。 - Azurespot
6
点表示相对导入,一个点表示当前目录,两个点表示父级目录,以此类推,一直追溯到根目录。 - dragon788

29

有所不同。在某些情况下,其中一个可能有效,而另一个则不行。以下是一个示例:假设我们有以下结构:

foo.py
mylib\
    a.py
    b.py

现在,我想将 b.py 导入到 a.py 中。同时,我希望将 a.py 导入到 foo 中。我应该如何做?在 a.py 中,我需要写两条语句:

import b

foo.py 中,我写道:
import mylib.a

如果尝试运行foo.py时,会生成一个ImportError。解释器会抱怨a.py文件中的导入语句(import b),说没有b模块。那么如何修复这个问题呢?在这种情况下,将a文件中的导入语句更改为import mylib.b并不能解决问题,因为ab都在mylib中。解决方案(或至少一个解决方案)是使用绝对导入:

from mylib import b

来源:Python:导入一个导入了模块的模块


4

您正在使用Python3中的urllib包。两种形式都可以接受,没有一种导入形式优于另一种。有时候,当涉及到多个包目录时,您可能需要使用前一种形式from x.y.z.a import s

在这种特定情况下,使用第二种方式import urllib.request和使用urllib.request是标准库统一使用的方式。


2

在Python 2.x中,你不能直接使用import urllib2.urlopen

你需要使用from urllib2 import urlopen

Python 2.6.5 (r265:79063, Apr 16 2010, 13:09:56)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import urllib2.urlopen
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named urlopen
>>> import urllib.request
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named request
>>>

2
那是因为urlopen是一个函数,对吧?这就像试图导入os.chdir一样——正如错误信息正确地指出的那样,“没有名为chdir的模块”……因为它不是一个模块! - wchargin

1
我对import urllib.request的主要抱怨是,即使没有导入urllib.parse,你仍然可以引用它。
>>> import urllib3.request
>>> urllib3.logging
<module 'logging' from '/usr/lib/python2.7/logging/__init__.pyc'>

还有一个请求是关于urllib3的。Python 2.7.4 ubuntu。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接