关于python:使用’import module’或’from module import’?

Use 'import module' or 'from module import'?

我试图找到一个全面的指南来说明使用import module还是from module import?我刚开始使用python,我试图从最佳实践开始。

基本上,我希望任何人都能分享他们的经验,其他开发人员有什么偏好,以及什么是最好的方法来避免路上出现任何问题?


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

import module

  • 赞成的意见:
    • 少维护你的import报表。不需要添加任何其他导入即可开始使用模块中的其他项
  • 欺骗:
    • 在代码中键入module.foo可能是冗长的(可以通过使用import module as mo来最小化冗长,然后键入mo.foo)

from module import foo

  • 赞成的意见:
    • 使用foo的输入较少
    • 对模块中哪些项可以访问的更多控制
  • 欺骗:
    • 要使用模块中的新项目,您必须更新您的import语句。
    • 你失去了关于foo的上下文。例如,与math.ceil()相比,ceil()的作用还不太清楚。

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

对于任何合理的大代码集,如果您import *,您很可能会将其固定到模块中,无法删除。这是因为很难确定代码中使用的哪些项来自"module",从而很容易达到您认为不再使用import的程度,但很难确定。


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

由于引用和名称绑定在python中的工作方式,如果您希望从模块外部更新模块中的某些符号(比如foo.bar),并让其他导入代码"see"发生更改,则必须以某种方式导入foo。例如:

模块FO:

1
bar ="apples"

模块A:

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

模块B:

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

但是,如果导入符号名而不是模块名,这将不起作用。

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

1
2
from foo import bar
bar ="oranges"

A之外没有代码会将条形图视为"橙色",因为我对条形图的设置只影响了模块A内的名称"条形图",它没有"触及"FOO模块对象并更新其"条形图"。


尽管很多人已经解释过importimport from,我还是想多解释一下引擎盖下面发生了什么,以及它变化的地方在哪里。

import foo

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

例如:foo.bar,而不是bar

from foo import bar

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

例如:bar,而不是bazfoo.baz

from foo import *

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

barbaz,但不包括_quxfoo._qux

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

1
2
>>> import sys
>>> import os.path

检查名称为osos.pathsys.modules号:

1
2
3
4
>>> 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'>

osos.path检查globals()locals()名称空间字典:

1
2
3
4
5
6
7
8
9
 >>> 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插入到本地和全局名称空间中。因此,我们应该能够使用:

1
2
3
4
5
6
7
 >>> 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

1
2
3
4
5
>>> path
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

一旦从locals()命名空间中删除os,即使它们存在于sys.modules中,也无法访问osos.path

1
2
3
4
5
6
7
8
9
10
>>> 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 fromfrom

1
2
>>> import sys
>>> from os import path

osos.path检查sys.modules

1
2
3
4
>>> 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()名称空间dicts中的外观:

1
2
3
4
5
6
7
8
9
>>> 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访问:

1
2
3
4
5
6
7
>>> 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':

1
2
3
4
5
6
>>> del locals()['path']
>>> path
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

最后一个使用别名的示例:

1
2
3
4
5
6
>>> 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'>
>>>

未定义路径:

1
2
3
4
5
>>> globals()['path']
Traceback (most recent call last):
 File"<stdin>", line 1, in <module>
KeyError: 'path'
>>>


这两种方法都有一个原因:有时一种方法比另一种方法更合适。

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

  • from module import ...:很好,导入的项目可以直接使用,没有模块名称前缀。缺点是你必须列出你所使用的每一件事情,并且在代码中不清楚事情的来源。

使用哪一个取决于哪一个使代码清晰易读,并且与个人偏好有着更多的关系。我倾向于使用import module,因为在代码中,很清楚对象或函数来自何处。在代码中经常使用一些对象/函数时,我使用from module import ...


我个人总是用

1
from package.subpackage.subsubpackage import module

然后访问所有内容

1
2
module.function
module.modulevar

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

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

当然,如果两个不同的包中的两个不同模块具有相同的模块名,例如

1
2
from package1.subpackage import module
from package2.subpackage import module

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


1
import module

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

1
from module import function

当您只需要function时,最好不要使用模块中的所有函数和类型来污染全局命名空间。


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

注意使用时

1
from package import item

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

相反,当使用类似

1
import item.subitem.subsubitem

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


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

如果模块foo使用以下导入:

1
from itertools import count

那么,模块bar可以错误地使用count,就好像它是在foo中定义的,而不是在itertools中定义的:

1
2
import foo
foo.count()

如果foo使用:

1
import itertools

这个错误仍然是可能的,但不太可能发生。bar需要:

1
2
import foo
foo.itertools.count()

这给我带来了一些麻烦。我有一个模块错误地从一个没有定义它的模块导入了一个异常,只从其他模块导入了它(使用from module import SomeException)。当不再需要和删除导入时,有问题的模块被破坏。


1
2
import package
import module

对于import,令牌必须是模块(包含python命令的文件)或包(sys.path中包含文件__init__.py的文件夹)。

当存在子包时:

1
2
import package1.package2.package
import package1.package2.module

文件夹(包)或文件(模块)的要求相同,但文件夹或文件必须在package2内,package1内,package1package2都必须包含__init__.py文件。https://docs.python.org/2/tutorial/modules.html网站

采用进口from样式:

1
2
from package1.package2 import package
from package1.package2 import module

包或模块以modulepackage而不是package1.package2.module的形式进入包含import语句的文件的命名空间。您可以始终绑定到更方便的名称:

1
a = big_package_name.subpackage.even_longer_subpackage_name.function

只有from类型的导入允许您命名特定的函数或变量:

1
from package3.module import some_function

是允许的,但是

1
import package3.module.some_function

是不允许的。


为了补充人们对from x import *所说的话:除了让人更难分辨名字来自何处之外,这让pylint这样的代码检查程序望而却步。他们会将这些名称报告为未定义的变量。


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

1。通用导入:

1
import math

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

1
math.sqrt(4)

当然,它增加了打字的工作量,但是作为一个初学者,它将帮助您跟踪与之相关的模块和函数(一个好的文本编辑器将显著减少打字的工作量,建议使用)。

使用此import语句可以进一步减少键入工作:

1
import math as m

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

2。函数导入:

1
from math import sqrt

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

三。通用进口:

1
from math import *

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

如果您有一个名为sqrt的函数,并且导入math,那么您的函数是安全的:有sqrt,有math.sqrt。但是,如果从math import*执行,则会遇到一个问题:即两个同名的不同函数。来源:codecademy


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

通常我更喜欢简单导入的自我记录风格,只会从..改为..当我必须键入模块名的次数超过10到20次时导入,即使只有一个模块正在导入。


导入模块-您不需要额外的工作来从模块中获取其他内容。它有一些缺点,比如重复输入

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