我试图找到一个全面的指南,是否最好使用导入模块或从模块导入。我刚刚开始学习Python,我正试图从最佳实践开始。

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


当前回答

因为我也是初学者,我将尝试用一种简单的方式解释这一点: 在Python中,我们有三种类型的import语句,分别是:

1. 一般进口:

import math

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

math.sqrt(4)

当然,它增加了输入工作,但作为初学者,它将帮助您跟踪与之相关的模块和函数(一个好的文本编辑器将大大减少输入工作,推荐使用)。

输入工作可以通过使用import语句进一步减少:

import math as m

现在,您可以使用m.s rt()而不是math.sqrt()。

2. 功能导入:

from math import sqrt

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

3.普遍的进口:

from math import * 

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

如果你有一个自己命名为sqrt的函数,并且你导入了math,你的函数是安全的:这是你的sqrt,这是math.sqrt。但是,如果从math import *执行,则会遇到一个问题:即,两个不同的函数具有完全相同的名称。来源:“

其他回答

我刚刚发现这两种方法之间还有一个微妙的区别。

如果模块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)。当不再需要导入并删除时,出现问题的模块就被破坏了。

这里还有另一个细节,没有提到,与写入模块有关。虽然这可能不太常见,但我时不时地需要它。

由于Python中引用和名称绑定的工作方式,如果你想更新模块中的某个符号,请输入foo。Bar,从模块外部,并有其他导入代码“看到”的变化,你必须以某种方式导入foo。例如:

模块foo:

bar = "apples"

模块一:

import foo
foo.bar = "oranges"   # update bar inside foo module object

模块2:

import foo           
print foo.bar        # if executed after a's "foo.bar" assignment, will print "oranges"

但是,如果你导入的是符号名而不是模块名,这就行不通了。

例如,如果我在模块a中这样做:

from foo import bar
bar = "oranges"

没有代码在一个外部将看到bar作为“橙子”,因为我的bar设置只是影响模块a中的名称“bar”,它没有“到达”foo模块对象并更新它的bar。

我个人总是用

from package.subpackage.subsubpackage import module

然后访问所有

module.function
module.modulevar

等。原因是,与此同时,您可以进行简短的调用,并且可以清楚地定义每个例程的模块名称空间,如果您必须在源代码中搜索给定模块的使用情况,这是非常有用的。

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

当然,如果在两个不同的包中对两个不同的模块使用相同的模块名,您可能会遇到麻烦,例如

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

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

尽管很多人已经解释了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'
>>>

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

. └─a └─b └─c

The import statement remembers all intermediate names. These names have to be qualified: 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)> The from ... import ... statement remembers only the imported name. This name must not be qualified: 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控制台。