526

我试图找到一个关于它是否最好使用import modulefrom module import. 我刚刚开始使用 Python,并且正在尝试从最佳实践入手。

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

4

21 回答 21

573

import module和之间的区别from module import foo主要是主观的。选择您最喜欢的一个,并在使用时保持一致。这里有一些要点可以帮助您做出决定。

import module

  • 优点:
    • 减少对import报表的维护。不需要添加任何额外的导入来开始使用模块中的另一个项目
  • 缺点:
    • 输入module.foo代码可能很乏味和冗余(可以通过使用import module as mothen typing来最小化乏味mo.foo

from module import foo

  • 优点:
    • 少打字使用foo
    • 更好地控制可以访问模块的哪些项目
  • 缺点:
    • 要使用模块中的新项目,您必须更新您的import声明
    • 你失去了关于foo. 例如,ceil()math.ceil()

任何一种方法都可以接受,但不要使用from module import *.

对于任何合理的大型代码集,如果您import *可能会将其固定到模块中,则无法删除。这是因为很难确定代码中使用的哪些项目来自“模块”,因此很容易达到您认为不再使用import但很难确定的地步。

于 2009-04-02T16:52:11.633 回答
233

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

由于引用和名称绑定在 Python 中的工作方式,如果您想从该模块外部更新模块中的某些符号,例如 foo.bar,并让其他导入代码“看到”该更改,则必须导入 foo a某种方式。例如:

模块 foo:

bar = "apples"

模块一:

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被视为“橙子”,因为我的设置bar仅影响了模块内部的名称“bar” a,它没有“进入”foo模块对象并更新其bar.

于 2013-10-04T16:10:12.673 回答
105

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


import foo

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

例如foo.bar但不是bar

from foo import bar

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

例如bar但不是bazfoo.baz

from foo import *

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

例如barandbaz但不是_quxor foo._qux


现在让我们看看我们什么时候做import X.Y

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

检查sys.modules名称osos.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'>

使用and来检查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,你将无法访问osos.path即使它们存在于 sys.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
>>>

现在让我们谈谈import from

from

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

检查sys.modules和:os_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'
>>>

您可以使用 namepath而不是 by访问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()

>>> 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'
>>>
于 2014-02-04T08:40:54.420 回答
44

两种方式都得到支持是有原因的:有时一种方式比另一种更合适。

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

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

使用哪个取决于哪个使代码清晰易读,并且与个人喜好有很大关系。我倾向于import module一般,因为在代码中非常清楚对象或函数的来源。当我在代码中大量from module import ...使用某些对象/函数时,我会使用它。

于 2009-04-02T16:50:35.100 回答
36

我个人总是使用

from package.subpackage.subsubpackage import module

然后访问所有内容

module.function
module.modulevar

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

不用说,不要使用 import *,因为它会污染你的命名空间,并且它不会告诉你给定函数来自哪里(来自哪个模块)

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

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

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

于 2009-04-02T17:03:54.257 回答
17
import module

当您将使用模块中的许多功能时最好。

from module import function

当您希望避免在只需要function.

于 2009-04-02T16:52:49.837 回答
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)。当不再需要并删除导入时,有问题的模块被破坏了。

于 2013-05-22T09:56:25.207 回答
11

这是另一个没有提到的区别。这是从http://docs.python.org/2/tutorial/modules.html逐字复制的

请注意,使用时

from package import item

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

相反,当使用类似的语法时

import item.subitem.subsubitem

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

于 2014-01-16T19:05:39.693 回答
8

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

1. 通用进口:

import math

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

math.sqrt(4)

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

使用以下 import 语句可以进一步减少打字工作:

import math as m

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

2.函数导入:

from math import sqrt

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

3.通用进口:

from math import * 

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

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

于 2018-05-05T12:59:06.703 回答
6
import package
import module

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

当有子包时:

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

对文件夹(包)或文件(模块)的要求是一样的,但文件夹或文件必须在里面package2,里面必须在里面package1,并且两者都package1必须package2包含__init__.py文件。https://docs.python.org/2/tutorial/modules.html

使用from导入样式:

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

包或模块进入包含import语句的文件的命名空间 as module(or 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 

不允许。

于 2015-02-22T05:37:51.653 回答
5

补充一下人们所说的from x import *:除了让人们更难以分辨名字的来源之外,这还会引发像 Pylint 这样的代码检查器。他们会将这些名称报告为未定义的变量。

于 2009-04-02T17:46:08.400 回答
5

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

.  
└─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 控制台。
于 2020-04-10T04:02:47.123 回答
4

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

通常我更喜欢普通导入的自我记录风格,并且只有在我必须输入模块名称的次数超过 10 到 20 时才更改为 from.. import,即使只有一个模块被导入。

于 2009-04-02T17:53:14.763 回答
3

我发现的显着差异之一令人惊讶的是没有人谈论过,使用普通导入可以访问private variable和从导入的模块,而使用from-import语句private functions是不可能的。

在此处输入图像描述

图片中的代码:

设置.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")

plain_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

from_importer.py

from settings import *
#print (_private_variable) #doesn't work
print (public_variable)
public_function()
#_private_function()   #doesn't work
于 2019-08-07T12:23:11.560 回答
3

我想补充一点。如果遇到循环导入,了解 Python 如何将导入的模块作为属性处理会很有用。

我有以下结构:

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

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

主要.py:

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

dis.dis 显示了差异(注意模块名称,abcd):

  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'

没有骰子

示例3

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

类似的问题......但显然 from x import y 与 import import xy as y 不同

例子4

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

这个也有效

于 2019-08-23T15:39:06.337 回答
2

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

模块之谜

from math import gcd
...

使用mymath

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

在较大的项目中,这种“最佳实践”允许我准确控制向后续导入披露的内容和不披露的内容。这使我的模块保持清洁并在一定规模的项目中得到回报。

于 2020-04-13T04:22:53.100 回答
2

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

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

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

于 2020-07-08T13:34:51.647 回答
1

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

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

于 2016-01-20T05:51:40.553 回答
1

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

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

因此,在代码中使用这些带有附加模块命名空间的类是否会添加一些新信息或只是延长代码可能会存在争议。

于 2019-07-17T12:23:28.527 回答
1

我正在回答一个类似的问题帖子,但在我发布之前,海报将其删除。这里有一个例子来说明差异。

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

package1
  |-- __init__.py

或者

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

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

让我们定义

  1. func1()在下 __init__.pymylibrary1并且
  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()
于 2021-02-03T22:25:15.347 回答
1

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

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

你的测试知道的实现细节越少越好。这样,如果你想出一个更好的解决方案(使用类而不是函数,使用额外的文件来分离想法等),你的测试中需要更改的内容更少以适应重构。

于 2021-06-14T17:59:23.573 回答