在Python中,最符合Python风格的导入模块方式是什么?

12

有人能向我建议在Python中导入模块的最佳方式吗?让我解释一下 - 我已经阅读了很多Python代码,并发现了几种不同的导入模块的方式,更确切地说是何时导入:

  1. 使用一个或多个包含整个项目所需的所有导入(第三方模块)的模块,因此所有导入都集中在少数模块中,易于维护。当任何单个模块需要导入任何模块时,它会向引用模块请求该模块。例如,在我们的项目中,我们有一个名为“references”的级别,因此它包含像“system.py”(包含对所有系统库的引用)、“platform.py”(包含对所有平台库的引用)、“devexpress.py”(包含对所有DevExpress库的引用)等模块。这些模块看起来像:
  2. 每个模块在顶部导入所有必要的类和函数 - 例如,项目中每个模块都有一个带有导入的部分。
  3. 每个函数/类在定义之后紧接着使用本地导入,例如仅导入它们真正需要的东西。

请参见以下示例。

1个导入模块示例 - 仅包含'import'和'from ... import ...'语句(没有任何方法或类):

#references.py
import re
import clr
import math

import System
import System.Text.RegularExpressions
import System.Random
import System.Threading
import System.DateTime

# System assemblies

clr.AddReference("System.Core")
clr.AddReference("System.Data")
clr.AddReference("System.Drawing")
...

#test.py
from references.syslibs import (Array, DataTable, OleDbConnection, OleDbDataAdapter,
                                 OleDbCommand, OleDbSchemaGuid)

def get_dict_from_data_table(dataTable):
    pass

使用'import'和'from ... import ...'导入2个模块,以及方法和类:

from ... import ...
from ... import ...

def Generate(param, param1 ...):
    pass

使用“import”和“from ... import ...”语句的3个模块,它们被用在方法和类中:

import clr
clr.AddReference("assembly")       

from ... import ...
...

def generate_(txt, param1, param2):
  from ... import ...
  from ... import ...
  from ... import ...

  if not cond(param1): res = "text"
  if not cond(param2): name = "default"

那么在Python中,最符合Python风格的导入模块方式是什么?

4个回答

17

重要的是不要使用from ... import *,其余都是口味问题,解决循环导入问题。 PEP 8 规定应在脚本顶部导入,但这也不是必须的。


谢谢回复。但从代码可读性的角度来看,使用1、2、3有什么好处?哪一个对大多数人来说更易读? - Artsiom Rudzenka
1
在代码顶部是最易读的,因为查看代码的人只需要参考一个地方就可以看到名称来自哪个包/模块。 - Ignacio Vazquez-Abrams

6

已经有人评论了主要的样式问题(在脚本顶部等),所以我会跳过这个。

对于我的导入,我通常按模块名称字母顺序排序(无论是“import”还是“from ... import ...”。我将其分成三组:标准库;第三方模块(来自pypi或其他);内部模块。

import os
import system

import twisted
import zope

import mymodule_1
import mymodule_2

1
我也是。我曾经参与过一个公司级别的PEP8风格指南,我们还决定在所有项目中使用完全相同的导入顺序。这个顺序是:1)Python库(如random、itertools等)2)从引用模块导入3)从核心模块导入4)为特定项目导入模块5)导入模块特定模块。 - Artsiom Rudzenka

3

Python的“import”将Python模块加载到自己的命名空间中,因此您必须在引用来自导入模块的任何名称之前添加模块名称后跟一个点。

import animals
animals.Elephant()

"from" 将一个 Python 模块加载到当前命名空间中,这样您就可以在不需要再次提及模块名称的情况下引用它。

from animals import Elephant
Elephant()

或者

from animals import *
Elephant()

使用from语句是不错的选择,但是使用通配符导入会被不鼓励。如果你有一个大规模项目,从不同的模块中导入可能会导致命名冲突。比如从两个不同的模块中导入Elephant()函数将会引起问题(就像使用通配符导入*一样)。因此,如果你有一个大规模项目,在其他模块中导入许多不同的东西,最好使用import语句,并使用module_name.your_class_or_function来使用导入的东西。否则,使用from语句即可...

我同意星号('*')是邪恶的。因此,我不久前仔细审查了我们所有的库,并删除了所有的import *语句。然而,我的问题与import语句的正确位置有关,而不是使用import还是from ... import...。谢谢你的回复。 - Artsiom Rudzenka
星号并不是邪恶的,它只需要小心使用。例如Tkinter,有一些库被设计为导入到当前命名空间中。 - Todd

3
请勿使用from module import *。这会污染命名空间,非常不受欢迎。但是,您可以使用from module import something导入特定的内容。这样可以保持命名空间的清洁。在大型项目中,如果使用通配符,可能会将2个foo或2个bar导入到同一命名空间中。 PEP 8建议将导入放在单独的行上。例如:
import os
import sys
import yourmodule
from yourmodule import specific_stuff

我做的一件事是将我的导入按照两组字母顺序排列。一组是标准/第三方的,另一组是内部模块。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接