我试图找到一份关于最好是使用import module
还是from module import
的综合指南?我刚刚开始使用Python,并且我试图从最初的实践开始。
基本上,我希望是否有人可以分享他们的经验,其他开发人员有什么偏好以及避免任何陷阱的最佳方法是什么?
答案 0 :(得分:393)
import module
和from 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
但不是baz
或foo.baz
from foo import *
导入foo
,并创建对当前命名空间中该模块定义的所有公共对象的引用(如果__all__
存在,则__all__
中列出的所有内容,否则所有不以_
)。不设置变量foo
。
E.g。 bar
和baz
但不是_qux
或foo._qux
。
现在让我们看看我们何时import X.Y
:
>>> import sys
>>> import os.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'>
使用globals()
和locals()
检查os
和os.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中,您也无法访问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
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'
>>>
您可以使用名称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 *
虽然它显着减少了打字工作但不建议使用,因为它会使用模块中的各种函数填充代码,并且它们的名称可能与用户定义函数的名称冲突。 示例:强>
答案 10 :(得分:4)
添加人们对from x import *
所说的内容:除了让人们更难分辨姓名的来源之外,这还会抛弃像Pylint这样的代码检查器。他们会将这些名称报告为未定义的变量。
答案 11 :(得分:3)
我自己的答案主要取决于我将使用多少个不同的模块。如果我只打算使用一两个,我会经常使用 from
... import
,因为它减少了击键次数在文件的其余部分,但如果我要使用许多不同的模块,我更喜欢 import
,因为这意味着每个模块引用都是自我记录的。我可以看到每个符号的来源,而不必四处寻找。
Usuaully我更喜欢普通导入的自我记录样式,只有当我输入模块名称的次数增加到10到20以上时才会更改为.. import,即使只导入了一个模块。
答案 12 :(得分:3)
这是我当前目录的目录结构:
. └─a └─b └─c
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)>
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)>
答案 13 :(得分:1)
我发现一个令人惊讶地没有人谈论的重大区别之一是,使用普通的 import 您可以访问private variable
和{{1 }}导入的模块中,而 from-import 语句则无法实现。
图片中的代码:
private functions
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")
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)
有些内置模块主要包含裸功能(base64,math,os,shutil,sys,time, ...),将这些裸露的函数 bound 绑定到某个命名空间绝对是一个好习惯,从而提高了代码的可读性。考虑没有这些名称空间的情况下,理解这些功能的含义会更加困难:
copysign(foo, bar)
monotonic()
copystat(foo, bar)
比将它们绑定到某个模块时要多:
math.copysign(foo, bar)
time.monotonic()
shutil.copystat(foo, bar)
有时甚至需要命名空间来避免不同模块之间的冲突(json.load与pickle.load)
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),但是值得注意的是,如果您需要考虑以下四个循环导入:
foo/
__init__.py
a.py
b.py
a.py:
import foo.b
b.py:
import foo.a
>>> import foo.a
>>>
这有效
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 import y与import import x.y和y不同
qux/
__init__.py
a.py
b.py
a.py:
import b
b.py:
import a
>>> import qux.a
>>>
这也有用
答案 18 :(得分:0)
因为很多人在这里回答,但我只是尽力而为:)
import module
导入哪个项目,最好使用 module
。这样,在出现问题时可能难以调试,因为
您不知道哪个项目有问题。
form module import <foo>
是最好的选择,当您知道需要导入哪个项目时,也有助于根据需要使用导入特定项目进行更多控制。使用这种方式进行调试可能很容易,因为您知道要导入的项目。
答案 19 :(得分:0)
我正在回答一个类似的问题帖子,但海报在我发布之前删除了它。下面是一个示例来说明差异。
Python 库可能有一个或多个文件(模块)。例如,
package1
|-- __init__.py
或
package2
|-- __init__.py
|-- module1.py
|-- module2.py
我们可以根据设计要求在任何文件中定义python函数或类。
让我们定义
func1()
在 __init__.py
下的 mylibrary1
中,以及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)
有很多答案,但没有一个提到测试(使用 unittest
或 pytest
)。
对外部模块使用 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')
您的测试了解的实现细节越少越好。这样,如果您想出更好的解决方案(使用类而不是函数,使用额外的文件来分离想法等),您的测试中需要更改以适应重构的次数就会减少。