我试图找到一个全面的指南,是否最好使用导入模块或从模块导入。我刚刚开始学习Python,我正试图从最佳实践开始。
基本上,我希望任何人都能分享他们的经验,其他开发者有什么偏好,以及避免任何陷阱的最佳方法是什么?
我试图找到一个全面的指南,是否最好使用导入模块或从模块导入。我刚刚开始学习Python,我正试图从最佳实践开始。
基本上,我希望任何人都能分享他们的经验,其他开发者有什么偏好,以及避免任何陷阱的最佳方法是什么?
当前回答
我刚刚发现这两种方法之间还有一个微妙的区别。
如果模块foo使用以下导入:
from itertools import count
这样,模块bar就会错误地使用count,就好像它是在foo中定义的,而不是在itertools中定义的一样:
import foo
foo.count()
如果foo使用:
import itertools
这种错误仍有可能发生,但不太可能发生。酒吧需要:
import foo
foo.itertools.count()
这给我带来了一些麻烦。我有一个模块错误地从一个没有定义它的模块导入了一个异常,只从其他模块导入了它(使用from module import SomeException)。当不再需要导入并删除时,出现问题的模块就被破坏了。
其他回答
支持这两种方法是有原因的:有时一种比另一种更合适。
导入模块:当你从模块中使用很多位的时候很好。缺点是需要用模块名限定每个引用。 从模块导入…:导入的项目可以直接使用,不需要模块名前缀。缺点是必须列出所使用的每一个东西,并且在代码中不清楚某些东西是从哪里来的。
使用哪种方法取决于哪种方法使代码清晰易读,并且与个人喜好有很大关系。我通常倾向于导入模块,因为在代码中,对象或函数的来源非常清楚。我使用from module import…当我在代码中经常使用一些对象/函数时。
尽管很多人已经解释了import和import from的区别,我还是想试着解释一下它背后发生了什么,以及它改变的所有地方在哪里。
进口foo:
导入foo,并在当前命名空间中创建对该模块的引用。然后需要定义完整的模块路径,以便从模块内部访问特定的属性或方法。
例如foo。酒吧但不是酒吧
从foo import bar:
导入foo,并创建对列出的所有成员(bar)的引用。不设置变量foo。
比如bar,而不是baz或者foo。baz
From foo import *:
导入foo,并在当前命名空间中创建对该模块定义的所有公共对象的引用(如果__all__存在,则__all__中列出的所有对象,否则所有不以_开头的对象)。不设置变量foo。
例如bar和baz,而不是_qux或foo._qux。
现在让我们看看什么时候导入X.Y:
>>> import sys
>>> import os.path
检查系统。命名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'>
使用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,你将不能访问os以及os。路径,即使它们存在于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:
来自:
>>> import sys
>>> from os import path
检查系统。包含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。我们所找到的模块与之前使用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'
>>>
你可以通过name 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'
>>>
我发现的一个显著区别是,令人惊讶的是,没有人讨论过使用纯导入,你可以从导入的模块中访问私有变量和私有函数,这是from-import语句无法实现的。
图像中的代码:
setting.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
import module和from module import foo之间的区别主要是主观的。选择一个你最喜欢的,并始终如一地使用它。这里有几点可以帮助你做决定。
导入模块
优点: 更少地维护您的导入语句。不需要添加任何额外的导入就可以开始使用模块中的另一个项 缺点: 输入模块。Foo在你的代码中可能是乏味和冗余的(单调可以通过使用import module作为mo然后输入mo. Foo来最小化)
从模块导入foo
优点: 使用foo时输入更少 对可以访问模块的哪些项有更多的控制 缺点: 要使用模块中的新项,必须更新import语句 你失去了关于foo的上下文。例如,与math.ceil()相比,ceil()的作用就不太清楚了。
这两种方法都可以,但不要使用from module import *。
对于任何合理的大型代码集,如果您导入*,则可能会将其固化到模块中,无法删除。这是因为很难确定代码中使用的哪些项来自'module',这很容易让你认为你不再使用导入,但很难确定。
正如Jan Wrobel提到的,不同导入的一个方面是导入的披露方式。
模块mymath
from math import gcd
...
使用mymath:
import mymath
mymath.gcd(30, 42) # will work though maybe not expected
如果我导入gcd只是为了内部使用,而不向mymath的用户公开它,这可能会很不方便。我经常遇到这种情况,在大多数情况下,我想“保持我的模块干净”。
除了Jan Wrobel提出的通过使用导入数学来掩盖这一点之外,我已经开始通过使用前导下划线来隐藏导入,以避免公开:
# for instance...
from math import gcd as _gcd
# or...
import math as _math
在较大的项目中,这种“最佳实践”允许我准确地控制向后续导入公开的内容和不公开的内容。这使我的模块保持干净,并在一定规模的项目中回报。