使用'导入模块'或'从模块导入'?

时间:2009-04-02 16:40:49

标签: python python-import

我试图找到一份关于最好是使用import module还是from module import的综合指南?我刚刚开始使用Python,并且我试图从最初的实践开始。

基本上,我希望是否有人可以分享他们的经验,其他开发人员有什么偏好以及避免任何陷阱的最佳方法是什么?

21 个答案:

答案 0 :(得分:393)

import modulefrom module import foo之间的差异主要是主观的。选择你最喜欢的那个,并在使用它时保持一致。以下是一些可以帮助您做出决定的要点。

import module

  • 优点:
    • 减少对import语句的维护。不需要添加任何其他导入来开始使用模块中的其他项目
  • 缺点:
    • 在代码中键入module.foo可能会很乏味且冗余(使用import module as mo然后键入mo.foo可以最大限度地减少乏味)

from module import foo

  • 优点:
    • 减少使用foo
    • 的输入
    • 可以更好地控制可以访问模块的哪些项目
  • 缺点:
    • 要使用模块中的新项目,您必须更新import声明
    • 您失去了关于foo的背景信息。例如,ceil()math.ceil()
    • 相比较不清楚

这两种方法都可以接受,但使用from module import *

对于任何合理的大量代码,如果您import *,您可能会将其粘贴到模块中,无法删除。这是因为很难确定代码中使用的项目来自“模块”,因此很容易达到您认为不再使用import的程度,但这很难一定不会。

答案 1 :(得分:104)

这里有另一个细节,未提及,与写入模块有关。虽然这可能不是很常见,但我不时需要它。

由于引用和名称绑定在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之外的任何代码都不会将条形图视为“oranges”,因为我的bar设置仅影响模块a中的名称“bar”,它没有“到达”foo模块对象并更新其“bar”。 / p>

答案 2 :(得分:56)

尽管许多人已经解释过import vs import from,但我想尝试更多地解释一下幕后发生的事情,以及它所改变的所有地方。


import foo

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

E.g。 foo.bar但不是bar

from foo import bar

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

E.g。 bar但不是bazfoo.baz

from foo import *

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

E.g。 barbaz但不是_quxfoo._qux


现在让我们看看我们何时import X.Y

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

使用名称sys.modulesos检查os.path

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

使用globals()locals()检查osos.path命名空间字符:

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

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

从locals()命名空间中删除os后,即使它们存在于sys.modules中,您也无法访问osos.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

使用sys.modulesos检查os.path

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

答案 3 :(得分:38)

支持这两种方式有一个原因:有时候一种方式比另一方更合适。

  • import module:当您使用模块中的许多位时很好。缺点是您需要使用模块名称限定每个引用。

  • from module import ...:很好,导入的项目可以在没有模块名称前缀的情况下直接使用。缺点是你必须列出你使用的每件东西,并且在代码中不清楚是什么东西来的。

使用哪种方法取决于哪些方法使代码清晰可读,并且与个人偏好有很多关系。我倾向于import module,因为在代码中,对象或函数的来源非常清楚。当我在代码中使用一些 lot 的对象/函数时,我使用from module import ...

答案 4 :(得分:32)

我个人总是使用

from package.subpackage.subsubpackage import module

然后以

的形式访问所有内容
module.function
module.modulevar

等。原因是同时你有很短的调用,并且你清楚地定义了每个例程的模块名称空间,如果你必须在源代码中搜索给定模块的使用,这是非常有用的。

毋庸置疑,请不要使用import *,因为它会污染您的命名空间,并且它不会告诉您给定函数的来源(来自哪个模块)

当然,如果两个不同软件包中的两个不同模块具有相同的模块名称,则可能会遇到麻烦,例如

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

在这种情况下,当然你会遇到麻烦,但是有一个强烈暗示你的包装布局存在缺陷,你必须重新考虑它。

答案 5 :(得分:13)

import module

最好使用模块中的许多功能。

from module import function

当您只需要function时,最好避免使用模块中的所有函数和类型来污染全局命名空间。

答案 6 :(得分:7)

这是另一个未提及的差异。这是从http://docs.python.org/2/tutorial/modules.html

逐字复制的

请注意,使用时

from package import item

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

相反,使用

之类的语法时
import item.subitem.subsubitem

每个项目除了最后一个必须是一个包;最后一项可以是模块或包,但不能是前一项中定义的类或函数或变量。

答案 7 :(得分:6)

我刚刚发现了这两种方法之间的另一个细微差别。

如果模块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)。当不再需要和删除导入时,违规模块就会被破坏。

答案 8 :(得分:4)

import package
import module

使用import,令牌必须是模块(包含Python命令的文件)或包(sys.path中包含文件__init__.py的文件夹。)

当有子包时:

import package1.package2.package
import package1.package2.module

文件夹(包)或文件(模块)的要求是相同的,但文件夹或文件必须位于package2内,package1必须在package1内,package2__init__.py必须包含from个文件。 https://docs.python.org/2/tutorial/modules.html

使用from package1.package2 import package from package1.package2 import module 导入方式:

import

包或模块将包含module语句的文件命名空间作为package(或package1.package2.module)而不是a = big_package_name.subpackage.even_longer_subpackage_name.function 。您始终可以绑定到更方便的名称:

from

只有from package3.module import some_function 导入样式允许您命名特定的函数或变量:

import package3.module.some_function 

是允许的,但是

{{1}}

是不允许的。

答案 9 :(得分:4)

由于我也是初学者,我将尝试以一种简单的方式解释这个问题: 在Python中,我们有三种类型的import语句:

<强> 1。通用导入:

import math

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

math.sqrt(4)

当然,它增加了打字工作,但作为一个初学者,它将帮助你跟踪与之相关的模块和功能,(一个好的文本编辑器将显着减少打字工作,建议)。

使用此导入语句可以进一步减少打字工作:

import math as m

现在,您可以使用math.sqrt()而非使用m.sqrt()

<强> 2。功能导入:

from math import sqrt

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

第3。通用进口:

from math import * 

虽然它显着减少了打字工作但不建议使用,因为它会使用模块中的各种函数填充代码,并且它们的名称可能与用户定义函数的名称冲突。 示例:

如果您拥有自己的名为sqrt的函数并导入数学,那么您的函数是安全的:有您的sqrt并且有math.sqrt。但是,如果您使用math import *,则会出现问题:即两个具有完全相同名称的不同函数。资料来源:Codecademy

答案 10 :(得分:4)

添加人们对from x import *所说的内容:除了让人们更难分辨姓名的来源之外,这还会抛弃像Pylint这样的代码检查器。他们会将这些名称报告为未定义的变量。

答案 11 :(得分:3)

我自己的答案主要取决于我将使用多少个不同的模块。如果我只打算使用一两个,我会经常使用 from ... import ,因为它减少了击键次数在文件的其余部分,但如果我要使用许多不同的模块,我更喜欢 import ,因为这意味着每个模块引用都是自我记录的。我可以看到每个符号的来源,而不必四处寻找。

Usuaully我更喜欢普通导入的自我记录样式,只有当我输入模块名称的次数增加到10到20以上时才会更改为.. import,即使只导入了一个模块。

答案 12 :(得分:3)

这是我当前目录的目录结构:

.  
└─a  
   └─b  
     └─c
  1. import语句会记住所有中间名称
    这些名称必须必须

    In[1]: import a.b.c
    
    In[2]: a
    Out[2]: <module 'a' (namespace)>
    
    In[3]: a.b
    Out[3]: <module 'a.b' (namespace)>
    
    In[4]: a.b.c
    Out[4]: <module 'a.b.c' (namespace)>
    
  2. from ... import ...语句仅记住导入的名称
    此名称不能合格:

    In[1]: from a.b import c
    
    In[2]: a
    NameError: name 'a' is not defined
    
    In[2]: a.b
    NameError: name 'a' is not defined
    
    In[3]: a.b.c
    NameError: name 'a' is not defined
    
    In[4]: c
    Out[4]: <module 'a.b.c' (namespace)>
    

  • 注意:当然,我在步骤1和2之间重新启动了Python控制台。

答案 13 :(得分:1)

我发现一个令人惊讶地没有人谈论的重大区别之一是,使用普通的 import 您可以访问private variable和{{1 }}导入的模块中,而 from-import 语句则无法实现。

enter image description here

图片中的代码:

setting.py

private functions

plain_importer.py

public_variable = 42
_private_variable = 141
def public_function():
    print("I'm a public function! yay!")
def _private_function():
    print("Ain't nobody accessing me from another module...usually")

from_importer.py

import settings
print (settings._private_variable)
print (settings.public_variable)
settings.public_function()
settings._private_function()

# Prints:
# 141
# 42
# I'm a public function! yay!
# Ain't nobody accessing me from another module...usually

答案 14 :(得分:1)

正如 Jan Wrobel 所提到的,不同进口的一方面是披露进口的方式。

模块神话

from math import gcd
...

神话的使用:

import mymath
mymath.gcd(30, 42)  # will work though maybe not expected

如果我仅为内部使用而导入了gcd,而不是将其透露给mymath的用户,这可能会带来不便。我经常遇到这种情况,在大多数情况下,我想“保持模块清洁”。

除了 Jan Wrobel 的建议(使用import math来掩盖这一点之外),我已经开始使用前导下划线来隐藏进口内容:

# for instance...
from math import gcd as _gcd
# or...
import math as _math

在较大的项目中,这种“最佳实践”使我能够精确控制后续进口中披露的内容和未披露的内容。这样可以使我的模块保持清洁,并以一定规模的项目进行投资。

答案 15 :(得分:0)

导入模块 - 您不需要额外的工作来从模块中获取另一个东西。它有缺点,如冗余打字

模块导入自 - 更少输入和更多控制模块的哪些项目可以访问。要使用模块中的新项目,您必须更新导入语句。

答案 16 :(得分:0)

有些内置模块主要包含裸功能(base64mathosshutilsystime, ...),将这些裸露的函数 bound 绑定到某个命名空间绝对是一个好习惯,从而提高了代码的可读性。考虑没有这些名称空间的情况下,理解这些功能的含义会更加困难:

copysign(foo, bar)
monotonic()
copystat(foo, bar)

比将它们绑定到某个模块时要多:

math.copysign(foo, bar)
time.monotonic()
shutil.copystat(foo, bar)

有时甚至需要命名空间来避免不同模块之间的冲突(json.loadpickle.load


另一方面,有些模块主要包含类(configparserdatetimetempfilezipfile,...),其中许多模块使类名自-足够解释:

configparser.RawConfigParser()
datetime.DateTime()
email.message.EmailMessage()
tempfile.NamedTemporaryFile()
zipfile.ZipFile()

因此可能存在争论,是将这些类与代码中的附加模块名称空间一起使用会增加一些新信息还是只是延长代码。

答案 17 :(得分:0)

我想补充一点,在导入调用期间需要考虑一些事项:

我具有以下结构:

mod/
    __init__.py
    main.py
    a.py
    b.py
    c.py
    d.py

main.py:

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

dis.dis显示了不同之处:

  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),但是值得注意的是,如果您需要考虑以下四个循环导入:

example1

foo/
   __init__.py
   a.py
   b.py
a.py:
import foo.b 
b.py:
import foo.a
>>> import foo.a
>>>

这有效

example2

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'

没有骰子

example3

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 import y与import import x.y和y不同

example4

qux/
   __init__.py
   a.py
   b.py
a.py:
import b 
b.py:
import a
>>> import qux.a
>>>

这也有用

答案 18 :(得分:0)

因为很多人在这里回答,但我只是尽力而为:)

    如果您不知道必须从import module导入哪个项目,最好使用
  1. module。这样,在出现问题时可能难以调试,因为 您不知道哪个项目有问题。

  2. form module import <foo>是最好的选择,当您知道需要导入哪个项目时,也有助于根据需要使用导入特定项目进行更多控制。使用这种方式进行调试可能很容易,因为您知道要导入的项目。

答案 19 :(得分:0)

我正在回答一个类似的问题帖子,但海报在我发布之前删除了它。下面是一个示例来说明差异。

Python 库可能有一个或多个文件(模块)。例如,

package1
  |-- __init__.py

package2
  |-- __init__.py
  |-- module1.py
  |-- module2.py

我们可以根据设计要求在任何文件中定义python函数或类。

让我们定义

  1. func1()__init__.py 下的 mylibrary1 中,以及
  2. foo()module2.py 下的 mylibrary2

我们可以使用其中一种方法访问 func1()

import package1

package1.func1()

import package1 as my

my.func1()

from package1 import func1

func1()

from package1 import *

func1()

我们可以使用以下方法之一访问foo()

import package2.module2

package2.module2.foo()

import package2.module2 as mod2

mod2.foo()

from package2 import module2

module2.foo()

from package2 import module2 as mod2

mod2.foo()

from package2.module2 import *

foo()

答案 20 :(得分:0)

有很多答案,但没有一个提到测试(使用 unittestpytest)。

tl;博士

对外部模块使用 import foo 以简化测试。

艰难的道路

从模块中单独导入类/函数 (from foo import bar) 会使红绿重构循环变得乏味。例如,如果我的文件看起来像

# my_module.py

from foo import bar


class Thing:
    def do_thing(self):
        bar('do a thing')

我的测试是

# test_my_module.py

from unittest.mock import patch
import my_module


patch.object(my_module, 'bar')
def test_do_thing(mock_bar):
    my_module.Thing().do_thing()
    mock_bar.assert_called_with('do a thing')

乍一看,这似乎很棒。但是如果我想在不同的文件中实现 Thing 类会发生什么?我的结构将不得不像这样改变......

# my_module.py

from tools import Thing


def do_thing():
    Thing().do_thing()


# tools.py

from foo import bar


class Thing:
    def do_thing(self):
        bar('do a thing')


# test_my_module.py

from unittest.mock import patch
import my_module
import tools  # Had to import implementation file...


patch.object(tools, 'bar')  # Changed patch
def test_do_thing(mock_bar):
    my_module.do_thing()  # Changed test (expected)
    mock_bar.assert_called_with('do a thing')

不幸的是,由于我使用了 from foo import bar,我需要更新我的补丁以引用 tools 模块。本质上,由于我的测试对实现了解太多,因此需要进行比预期更多的更改才能进行此重构。

更好的方法

使用 import foo,我的测试可以忽略模块的实现方式,只需修补整个模块。

# my_module.py

from tools import Thing


def do_thing():
    Thing().do_thing()


# tools.py

import foo


class Thing:
    def do_thing(self):
        foo.bar('do a thing')  # Specify 'bar' is from 'foo' module


# test_my_module.py

from unittest.mock import patch
import my_module


patch('foo')  # Patch entire foo module
def test_do_thing(mock_foo):
    my_module.do_thing()  # Changed test (expected)
    mock_foo.bar.assert_called_with('do a thing')

您的测试了解的实现细节越少越好。这样,如果您想出更好的解决方案(使用类而不是函数,使用额外的文件来分离想法等),您的测试中需要更改以适应重构的次数就会减少。