我曾试图找到一份全面的指南,来判断何时最好使用import module
或者from module import
。我刚接触Python编程语言,希望从一开始就遵循最佳实践。
基本上,我希望有人能分享他们的经验,其他开发人员的偏好以及避免任何后续问题的最佳方法。
我曾试图找到一份全面的指南,来判断何时最好使用import module
或者from module import
。我刚接触Python编程语言,希望从一开始就遵循最佳实践。
基本上,我希望有人能分享他们的经验,其他开发人员的偏好以及避免任何后续问题的最佳方法。
import
语句维护较少。不需要添加任何其他导入即可开始使用模块中的另一个项module.foo
可能很繁琐和冗余(可以通过import module as mo
来将其简化为mo.foo
)
<代码>from module import foo
优点:
- 使用foo
时输入更少
- 更好地控制可以访问模块的哪些项import
语句
- 您失去了关于foo
的上下文信息。例如,与math.ceil()
相比,ceil()
的含义不太清晰from module import *
。import *
,则很可能会将其固定到模块中,无法删除。这是因为很难确定代码中使用的哪些项来自“模块”,这使得很容易到达您认为不再使用import
,但极难确定的程度。from module import *
可以特别有用,如果像这样使用它:if(windows):\n\t from module_win import * \n else: \n\t from module_lin import *
。然后,如果module_lin和module_win中的函数名相同,你的父模块可以潜在地包含与操作系统无关的函数名。这类似于有条件地继承两个类之一。 - anishsanebar = "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"
from foo import bar
bar = "oranges"
除了模块 a
中的代码外,没有其他代码会将 bar
视为 "oranges",因为我对 bar
的设置仅影响模块 a
内的名称 "bar",它没有 "触及" foo
模块对象并更新其 bar
。
import
和 from import
的区别,但我想尝试更详细地解释一下底层发生了什么以及它所改变的所有地方。
import foo
:导入 foo
并在当前命名空间中创建对该模块的引用。然后需要定义完成的模块路径才能从模块内部访问特定属性或方法。
例如:foo.bar
而不是 bar
from foo import bar
:导入 foo
并创建对列出的所有成员(bar
)的引用。不设置变量 foo
。
例如:bar
而不是 baz
或 foo.baz
from foo import *
:导入 foo
并在当前命名空间中创建对该模块中定义的所有公共对象的引用(如果存在 __all__
则为其中列出的所有内容,否则为不以 _
开头的所有内容)。不设置变量 foo
。
例如:bar
和 baz
而不是 _qux
或 foo._qux
。
现在让我们看看当我们执行 import X.Y
时会发生什么:
>>> import sys
>>> import os.path
检查具有名称 os
和 os.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'>
使用 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
<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
os
和 os.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'
>>>
as SYMBOL
会改变这个答案的工作方式吗? - Maximilian Burszley支持两种方式是有原因的:在某些情况下,一种方式比另一种更合适。
import module
:当您使用模块中的许多组成部分时,这很好。缺点是您需要在每个引用中加上模块名称限定符。
from module import ...
:已导入的项目可以直接使用而无需模块名称前缀。缺点是必须列出每个使用的东西,并且在代码中不清楚某物来自哪里。
使用哪种方式取决于哪种使代码清晰易读,并与个人偏好有很大关系。通常我倾向于使用 import module
,因为在代码中非常清楚对象或函数来自哪里。当我在代码中使用某个对象/函数很多次时,我会使用 from module import ...
。
from M import X
并且仍然从某种程度上获得使用限定符的好处?如果您在导入之后仍然可以执行 M.X
,似乎您可以兼顾两全。 - arthropodclass m: from something.too.long import x, y, z
。但是我并不是特别推荐这么做。 - Lie Ryan我个人总是使用
from package.subpackage.subsubpackage import module
然后作为一切的访问
module.function
module.modulevar
等等。原因是你可以同时进行简短的调用,而且你可以清晰地定义每个例程的模块命名空间,这对于在源代码中搜索给定模块的使用情况非常有用。
不用import *,因为它会污染你的命名空间,而且它不会告诉你一个给定函数来自哪个模块。
当然,如果你在两个不同的包中有两个不同的模块具有相同的模块名称,那么你可能会遇到麻烦,例如:
from package1.subpackage import module
from package2.subpackage import module
在这种情况下,当然会遇到麻烦,但是这强烈暗示您的软件包布局存在缺陷,需要重新考虑。
pathlib
时,你总是写成 pathlib.Path
吗? - run_the_raceimport module
当你需要使用一个模块中的许多函数时,最好使用它。
from module import function
当你只需要一个function
时,使用命名空间是最好的方式,可以避免将模块中的所有函数和类型污染全局命名空间。
我刚刚发现这两种方法之间还有一个微妙的区别。
如果模块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
)。当这个导入不再需要并且被移除时,有问题的模块就会出现故障。
这里有另一个未提及的区别。以下是从http://docs.python.org/2/tutorial/modules.html直接复制的:
请注意,在使用
from package import item
该项可以是包的子模块(或子包),也可以是包中定义的其他名称,例如函数、类或变量。导入语句首先测试该项是否在包中定义;如果没有,则假定它是一个模块并尝试加载它。如果找不到它,则引发ImportError异常。
相反,当使用像
import item.subitem.subsubitem
除了最后一个项目可以是模块或包之外,其余每个项目都必须是包;最后一个项目不能是前面定义的类、函数或变量。
作为一名初学者,我会尝试以简单的方式来解释这个问题:
在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 *
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)
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 导入 y 不同于将 x.y 作为 y 导入
qux/
__init__.py
a.py
b.py
a.py:
import b
b.py:
import a
>>> import qux.a
>>>
这个也可以工作
from ... import ...
语法的原因 和 'import module' vs. 'from module import function' - RBT'from module import X,Y,Z'
和'from module import *'
之间有很大的区别。后者会污染你的命名空间,并且可能会因模块中发生的情况而导致不可预测的结果。更糟糕的是,使用多个模块进行from module import *
。 - smciimport
和from
语句的工作逻辑。 - Konstantin Burlachenko