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

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


当前回答

有一些内置模块主要包含裸函数(base64, math, os, shutil, sys, time,…),将这些裸函数绑定到某个名称空间绝对是一个很好的实践,从而提高代码的可读性。想想看,如果没有命名空间,要理解这些函数的含义是多么困难:

copysign(foo, bar)
monotonic()
copystat(foo, bar)

当它们被绑定到某个模块时:

math.copysign(foo, bar)
time.monotonic()
shutil.copystat(foo, bar)

有时你甚至需要命名空间来避免不同模块之间的冲突(json. xml)。Load vs. pickle.load) 另一方面,有些模块包含大部分类(configparser, datetime, tempfile, zipfile,…),其中许多模块的类名不言自明:

configparser.RawConfigParser()
datetime.DateTime()
email.message.EmailMessage()
tempfile.NamedTemporaryFile()
zipfile.ZipFile()

因此,在代码中使用这些类和额外的模块名称空间是增加了一些新信息还是只是延长了代码,可能会有争论。

其他回答

我个人总是用

from package.subpackage.subsubpackage import module

然后访问所有

module.function
module.modulevar

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

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

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

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

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

支持这两种方法是有原因的:有时一种比另一种更合适。

导入模块:当你从模块中使用很多位的时候很好。缺点是需要用模块名限定每个引用。 从模块导入…:导入的项目可以直接使用,不需要模块名前缀。缺点是必须列出所使用的每一个东西,并且在代码中不清楚某些东西是从哪里来的。

使用哪种方法取决于哪种方法使代码清晰易读,并且与个人喜好有很大关系。我通常倾向于导入模块,因为在代码中,对象或函数的来源非常清楚。我使用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'
>>>
import package
import module

对于import,令牌必须是一个模块(包含Python命令的文件)或一个包(sys。包含文件__init__.py的路径。)

当有子包时:

import package1.package2.package
import package1.package2.module

对文件夹(包)或文件(模块)的要求是相同的,但文件夹或文件必须在package2中,而package2必须在package1中,并且package1和package2都必须包含__init__.py文件。https://docs.python.org/2/tutorial/modules.html

使用import的from样式:

from package1.package2 import package
from package1.package2 import module

包或模块进入包含import语句的文件的命名空间为module(或包),而不是package1.package2.module。你总是可以绑定到一个更方便的名字:

a = big_package_name.subpackage.even_longer_subpackage_name.function

只有import的from样式允许你命名一个特定的函数或变量:

from package3.module import some_function

是允许的,但是

import package3.module.some_function 

是不允许的。

我还想补充一点。如果遇到循环导入,了解Python如何将导入的模块作为属性处理可能会很有用。

我有以下结构:

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)

最后它们看起来是一样的(STORE_NAME在每个例子中都是result),但如果你需要考虑以下四个循环导入,这是值得注意的:

例二

foo/
   __init__.py
   a.py
   b.py
a.py:
import foo.b 
b.py:
import foo.a
>>> import foo.a
>>>

这是

example2

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并不等于从y导入x

example4

qux/
   __init__.py
   a.py
   b.py
a.py:
import b 
b.py:
import a
>>> import qux.a
>>>

这个也可以