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

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


当前回答

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
>>>

这个也可以

我发现的一个显著区别是,令人惊讶的是,没有人讨论过使用纯导入,你可以从导入的模块中访问私有变量和私有函数,这是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

正如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

在较大的项目中,这种“最佳实践”允许我准确地控制向后续导入公开的内容和不公开的内容。这使我的模块保持干净,并在一定规模的项目中回报。

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

. └─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控制台。

有一些内置模块主要包含裸函数(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()

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