使用 'import module' 还是 'from module import'?

603

我曾试图找到一份全面的指南,来判断何时最好使用import module或者from module import。我刚接触Python编程语言,希望从一开始就遵循最佳实践。

基本上,我希望有人能分享他们的经验,其他开发人员的偏好以及避免任何后续问题的最佳方法。


20
我想让你知道,被选择的答案是错误的。它声称差异是主观的,然而实际上存在差异。这可能会导致难以检测到的错误。请参考Michael Ray Lovett的回答。 - Mayou36
5
'from module import X,Y,Z''from module import *'之间有很大的区别。后者会污染你的命名空间,并且可能会因模块中发生的情况而导致不可预测的结果。更糟糕的是,使用多个模块进行from module import * - smci
Python语言没有标准,但有一本不错的书,即Python 3.*参考手册,最初由Python的创始人Guido Van Rossum编写:https://docs.python.org/3/tutorial/ - Konstantin Burlachenko
另一个文档:https://docs.python.org/3/reference/simple_stmts.html#the-import-statement 描述了各种语句,并从该文档中描述了importfrom语句的工作逻辑。 - Konstantin Burlachenko
显示剩余5条评论
23个回答

617
<代码>import module和<代码>from module import foo之间的区别主要是主观的。选择您最喜欢的方法并在使用时保持一致。以下是一些帮助您做出决定的要点。 <代码>import module 优点: - 您的import语句维护较少。不需要添加任何其他导入即可开始使用模块中的另一个项
缺点: - 在您的代码中键入module.foo可能很繁琐和冗余(可以通过import module as mo来将其简化为mo.foo) <代码>from module import foo 优点: - 使用foo时输入更少 - 更好地控制可以访问模块的哪些项
缺点: - 要使用模块中的新项,您必须更新import语句 - 您失去了关于foo的上下文信息。例如,与math.ceil()相比,ceil()的含义不太清晰
两种方法都可以接受,但不要使用from module import *
对于任何合理大的代码集,如果您使用import *,则很可能会将其固定到模块中,无法删除。这是因为很难确定代码中使用的哪些项来自“模块”,这使得很容易到达您认为不再使用import,但极难确定的程度。

113
鼓励不使用“from module import *”,因为这会使命名空间变得混乱。 +1 - Christian Witts
33
在“import *”中,命名空间混乱并不是最棘手的问题,降低可读性才是:任何名称冲突都会在(单元)测试中显示。但你使用的导入模块中所有名称都是裸露的,几乎没有提示它们来自哪里。我绝对讨厌“import *”。 - Jürgen A. Erhard
37
Python之禅不是说显式优于隐式吗? - Antony Koch
10
from module import *可以特别有用,如果像这样使用它:if(windows):\n\t from module_win import * \n else: \n\t from module_lin import *。然后,如果module_lin和module_win中的函数名相同,你的父模块可以潜在地包含与操作系统无关的函数名。这类似于有条件地继承两个类之一。 - anishsane
29
@anishsane. 还有另外一种方法可以做到。导入 module_win 作为 something。然后始终使用 something.method_name()。 - Vinay
显示剩余17条评论

285
这里还有一个细节,未提到与模块写入相关。虽然可能不太常见,但我有时需要这样做。
由于Python中引用和名称绑定的工作方式,如果您想从模块外部更新某个符号(例如foo.bar)并让其他导入的代码“看到”该更改,则必须以某种方式导入foo。例如:
模块foo:
bar = "apples"

模块a:

import foo
foo.bar = "oranges"   # update bar inside foo module object

模块 b:

import foo           
print foo.bar        # if executed after a's "foo.bar" assignment, will print "oranges"

然而,如果您导入符号名称而不是模块名称,则无法正常工作。
例如,在模块a中执行以下操作:
from foo import bar
bar = "oranges"

除了模块 a 中的代码外,没有其他代码会将 bar 视为 "oranges",因为我对 bar 的设置仅影响模块 a 内的名称 "bar",它没有 "触及" foo 模块对象并更新其 bar


4
不,最后一个例子中,“foo”这个名称是未知的。 - Ghislain Leveque
80
这个回答提供了关于两种导入变体之间区别的“真正”答案。 - Mayou36
5
写了一些代码片段来证明这个答案是绝对正确的,但是背后的原理是什么? - huangbeidu
4
这并非完全正确。所述情况是由于字符串为不可变类型而产生的。如果将“bar”改为列表,则在模块a中使用“foo.bar.append('oranges')”后,在模块b中打印该列表时会反映此修改。 - rohit_r
2
尽管我同意这个答案的技术性,但我想指出这是一个不好的实践。为了避免非常难以发现的错误,您应该尽可能避免改变全局变量。多个模块更改全局变量会呈指数级增加此风险。请永远不要这样做。 - Chris Collett
显示剩余8条评论

122
尽管很多人已经解释了 importfrom import 的区别,但我想尝试更详细地解释一下底层发生了什么以及它所改变的所有地方。

import foo:

导入 foo 并在当前命名空间中创建对该模块的引用。然后需要定义完成的模块路径才能从模块内部访问特定属性或方法。

例如:foo.bar 而不是 bar

from foo import bar:

导入 foo 并创建对列出的所有成员(bar)的引用。不设置变量 foo

例如:bar 而不是 bazfoo.baz

from foo import *:

导入 foo 并在当前命名空间中创建对该模块中定义的所有公共对象的引用(如果存在 __all__ 则为其中列出的所有内容,否则为不以 _ 开头的所有内容)。不设置变量 foo

例如:barbaz 而不是 _quxfoo._qux


现在让我们看看当我们执行 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'>

使用 osos.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
<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
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

如果您从locals()命名空间中删除了os,那么即使它们存在于sys.modules中,您也将无法访问os以及os.path

>>> 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
>>>

现在让我们谈谈import from

from

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

使用 osos.path 检查 sys.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'
>>>

16
虽然这个回答有点啰嗦,但它确实是列表中对于一个相当复杂的问题最好的答案。它提供了实际的代码来帮助解释“底层”微妙之处,对于这个特定的问题,这比风格更重要。我希望我可以给它多次点赞! - Mike Williamson
1
使用 as SYMBOL 会改变这个答案的工作方式吗? - Maximilian Burszley

45

支持两种方式是有原因的:在某些情况下,一种方式比另一种更合适。

  • import module:当您使用模块中的许多组成部分时,这很好。缺点是您需要在每个引用中加上模块名称限定符。

  • from module import ...:已导入的项目可以直接使用而无需模块名称前缀。缺点是必须列出每个使用的东西,并且在代码中不清楚某物来自哪里。

使用哪种方式取决于哪种使代码清晰易读,并与个人偏好有很大关系。通常我倾向于使用 import module,因为在代码中非常清楚对象或函数来自哪里。当我在代码中使用某个对象/函数很多次时,我会使用 from module import ...


1
有没有办法使用 from M import X 并且仍然从某种程度上获得使用限定符的好处?如果您在导入之后仍然可以执行 M.X,似乎您可以兼顾两全。 - arthropod
@artgropod:有点儿。你可以这样写 class m: from something.too.long import x, y, z。但是我并不是特别推荐这么做。 - Lie Ryan

35

我个人总是使用

from package.subpackage.subsubpackage import module

然后作为一切的访问

module.function
module.modulevar

等等。原因是你可以同时进行简短的调用,而且你可以清晰地定义每个例程的模块命名空间,这对于在源代码中搜索给定模块的使用情况非常有用。

不用import *,因为它会污染你的命名空间,而且它不会告诉你一个给定函数来自哪个模块。

当然,如果你在两个不同的包中有两个不同的模块具有相同的模块名称,那么你可能会遇到麻烦,例如:

from package1.subpackage import module
from package2.subpackage import module

在这种情况下,当然会遇到麻烦,但是这强烈暗示您的软件包布局存在缺陷,需要重新考虑。


11
在最后一种情况下,你可以始终使用: import pkgN.sub.module as modN 为每个模块提供不同的名称。你也可以使用“import modulename as mod1”模式来缩短一个长名称,或者通过单个名称更改在相同API下的实现(例如DB API模块)来切换。 - Jeff Shannon
当你使用 pathlib 时,你总是写成 pathlib.Path 吗? - run_the_race

16
import module

当你需要使用一个模块中的许多函数时,最好使用它。

from module import function

当你只需要一个function时,使用命名空间是最好的方式,可以避免将模块中的所有函数和类型污染全局命名空间。


14
如果你执行的是“import module”语句,那么在全局名称空间中唯一存在的就是“module”。只有当你执行“from .. import *”语句时才会污染名称空间。 - John Fouhy

12

我刚刚发现这两种方法之间还有一个微妙的区别。

如果模块foo使用以下导入方式:

from itertools import count

然后模块bar可能会错误地将count用作在foo而不是itertools中定义的变量:

import foo
foo.count()

如果 foo 使用:
import itertools

错误仍然有可能发生,但是发生的可能性较小。 bar 需要:
import foo
foo.itertools.count()

这给我带来了一些麻烦。我有一个模块错误地从没有定义异常的模块中导入了一个异常,只是从另一个模块中导入了它(使用 from module import SomeException)。当这个导入不再需要并且被移除时,有问题的模块就会出现故障。


10

这里有另一个未提及的区别。以下是从http://docs.python.org/2/tutorial/modules.html直接复制的:

请注意,在使用

from package import item

该项可以是包的子模块(或子包),也可以是包中定义的其他名称,例如函数、类或变量。导入语句首先测试该项是否在包中定义;如果没有,则假定它是一个模块并尝试加载它。如果找不到它,则引发ImportError异常。

相反,当使用像

import item.subitem.subsubitem

除了最后一个项目可以是模块或包之外,其余每个项目都必须是包;最后一个项目不能是前面定义的类、函数或变量。


我注意到的另一件事是,如果项目也是包内的子模块,则"from package import item"可以工作,但是"import package"在包的空__init__.py下不起作用,除非我们在包的__init__文件中有"import item"。 - Amitoz Dandiana

8

作为一名初学者,我会尝试以简单的方式来解释这个问题:

在Python中,我们有三种类型的import语句,它们分别是:

1. 通用导入:

import math

这种类型的导入是我个人最喜欢的,唯一的缺点是如果需要使用任何模块的函数,则必须使用以下语法:

math.sqrt(4)

当然,这会增加打字的工作量,但对于初学者来说,这将有助于您跟踪与模块和函数相关联的内容(一个好的文本编辑器可以显著减少打字工作量,并且建议使用)。
使用此导入语句可以进一步减少打字工作量:
import math as m

现在,您可以使用m.sqrt()代替math.sqrt()

2. 函数导入:

from math import sqrt

这种类型的导入适用于您的代码只需要访问模块中单个或几个函数,但是如果要使用模块中的任何新项目,您必须更新导入语句。

3. 通用导入:

from math import * 

尽管这种方法显著减少了输入工作量,但不建议使用,因为它会在您的代码中填充各种模块函数及其名称可能与用户定义函数的名称冲突。
例如:如果您有一个自己命名为sqrt的函数,并导入了math模块,则您的函数是安全的:其中包含您的sqrt和math.sqrt。但是,如果您使用from math import *,则会产生问题:即具有完全相同名称的两个不同函数。来源:Codecademy

7
我希望补充一点内容。 如果您遇到循环导入,了解Python如何将导入的模块作为属性处理可能会很有用。
我有以下结构:
mod/
    __init__.py
    main.py
    a.py
    b.py
    c.py
    d.py

我将使用不同的导入方法从main.py导入其他模块

main.py:

import mod.a
import mod.b as b
from mod import c
import d

dis.dis 展示差异(请注意模块名称 a b c d):

  1           0 LOAD_CONST               0 (-1)
              3 LOAD_CONST               1 (None)
              6 IMPORT_NAME              0 (mod.a)
              9 STORE_NAME               1 (mod)

  2          12 LOAD_CONST               0 (-1)
             15 LOAD_CONST               1 (None)
             18 IMPORT_NAME              2 (b)
             21 STORE_NAME               2 (b)

  3          24 LOAD_CONST               0 (-1)
             27 LOAD_CONST               2 (('c',))
             30 IMPORT_NAME              1 (mod)
             33 IMPORT_FROM              3 (c)
             36 STORE_NAME               3 (c)
             39 POP_TOP

  4          40 LOAD_CONST               0 (-1)
             43 LOAD_CONST               1 (None)
             46 IMPORT_NAME              4 (mod.d)
             49 LOAD_ATTR                5 (d)
             52 STORE_NAME               5 (d)
             55 LOAD_CONST               1 (None)

最终它们看起来是相同的(STORE_NAME在每个示例中都是结果),但如果您需要考虑以下四个循环导入,则值得注意:

示例1

foo/
   __init__.py
   a.py
   b.py

a.py:
import foo.b 

b.py:
import foo.a

>>> import foo.a
>>>

这个有效。

例子2

bar/
   __init__.py
   a.py
   b.py

a.py:
import bar.b as b

b.py:
import bar.a as a

>>> import bar.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "bar\a.py", line 1, in <module>
    import bar.b as b
  File "bar\b.py", line 1, in <module>
    import bar.a as a
AttributeError: 'module' object has no attribute 'a'

没戏

例子三

baz/
   __init__.py
   a.py
   b.py

a.py:
from baz import b

b.py:
from baz import a

>>> import baz.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "baz\a.py", line 1, in <module>
    from baz import b
  File "baz\b.py", line 1, in <module>
    from baz import a
ImportError: cannot import name a

类似的问题...但明显从 x 导入 y 不同于将 x.y 作为 y 导入

示例4

qux/
   __init__.py
   a.py
   b.py

a.py:
import b 

b.py:
import a

>>> import qux.a
>>>

这个也可以工作


2
惊人的有趣事实!你能解释一下背后的原因吗? - Jzou
1
好问题!我不知道答案,但这听起来像是一个有趣的探险Python内部的练习。 - ahfx
1
只有这个答案提供了一些深度,解释了当导入类型之间的差异如此根本时,一个是“不可行”的(import-from),而另一个“可行”(import或from ... import *)的情况。在某些情况下(例如需要/使用依赖注入的情况下),循环依赖是不可避免的。目前看来,import和from ... import *在C ++中作为“包含保护”工作(仅需要符号名称),但是import-from语句实际上需要完全加载目标模块。需要更多的理解... - P Marecki
1
很不幸的是,很难找到“部分初始化模块”在模块加载过程中的具体含义;虽然有大量关于如何“修复”它的结果,但却很少涉及到每个导入语句在模块的加载/初始化过程中实际进行了哪些操作……以及这是否是在语言参考中规定的,还是只是特定实现的“特性”,可能会在下一个版本的CPython(或其他解释器)中消失。 - P Marecki

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