对于 Python 导入,什么是好的经验法则?

我对在 Python 中导入模块的多种方式感到有点困惑。

import X
import X as Y
from A import B

我一直在阅读关于范围和名称空间的文章,但是我希望得到一些关于什么是最佳策略、在什么情况下以及为什么的实用建议。导入应该发生在模块级还是方法/功能级?在 __init__.py中还是在模块代码本身中?

我的问题并没有真正得到“ Python 包——按类导入,而不是按文件导入”的回答,尽管它显然是相关的。

52631 次浏览

我通常会在模块级别使用 import X。如果您只需要一个单一的对象从一个模块,使用 from X import Y

只有在遇到名称冲突时才使用 import X as Y

当模块被用作主模块时,我只在函数级别使用导入来导入我需要的内容,比如:

def main():
import sys
if len(sys.argv) > 1:
pass

高温

在我们公司的生产代码中,我们尽量遵循以下规则。

我们把导入放在文件的开头,紧挨着主文件的 docstring,例如:

"""
Registry related functionality.
"""
import wx
# ...

现在,如果我们导入一个类,它是导入模块中为数不多的类之一,我们直接导入名称,这样在代码中我们只需要使用最后一部分,例如:

from RegistryController import RegistryController
from ui.windows.lists import ListCtrl, DynamicListCtrl

但是,有些模块包含几十个类,例如所有可能的异常的列表。然后我们导入模块本身并在代码中引用它:

from main.core import Exceptions
# ...
raise Exceptions.FileNotFound()

我们尽可能少地使用 import X as Y,因为它使得搜索特定模块或类的用法变得困难。然而,有时候,如果你想导入两个名字相同但存在于不同模块中的类,你必须使用它,例如:

from Queue import Queue
from main.core.MessageQueue import Queue as MessageQueue

作为一般规则,我们不在方法内部进行导入——它们只会使代码变得更慢、更不可读。有些人可能会发现这是一种很容易解决循环导入问题的好方法,但是更好的解决方案是代码重组。

如果同一个模块/类有不同的实现,那么 import X as Y就很有用。

通过一些嵌套的 try..import..except ImportError..import,你可以在代码中隐藏实现。参见 Lxml 树导入示例:

try:
from lxml import etree
print("running with lxml.etree")
except ImportError:
try:
# Python 2.5
import xml.etree.cElementTree as etree
print("running with cElementTree on Python 2.5+")
except ImportError:
try:
# Python 2.5
import xml.etree.ElementTree as etree
print("running with ElementTree on Python 2.5+")
except ImportError:
try:
# normal cElementTree install
import cElementTree as etree
print("running with cElementTree")
except ImportError:
try:
# normal ElementTree install
import elementtree.ElementTree as etree
print("running with ElementTree")
except ImportError:
print("Failed to import ElementTree from any known place")

我通常尝试使用常规的 import modulename,除非模块名很长,或者经常使用。

比如,我会..。

from BeautifulSoup import BeautifulStoneSoup as BSS

. . 所以我可以做 soup = BSS(html)而不是 BeautifulSoup.BeautifulStoneSoup(html)

或者。

from xmpp import XmppClientBase

. . 而不是当我只使用 XmppClientBase 时导入整个 xmpp

如果您想要导入非常长的方法名,或者防止重复现有的导入/变量/类/方法(您应该试图完全避免这种情况,但这并不总是可能的) ,那么使用 import x as y是很方便的

假设我想从另一个脚本运行一个 main ()函数,但是我已经有一个 main ()函数。

from my_other_module import main as other_module_main

. . 不会将我的 main函数替换为我的 _ other _ module 的 main函数

哦,还有一件事——不要做 from x import *——它会让你的代码非常难以理解,因为你不能很容易地看到一个方法是从哪里来的(from x import *; from y import *; my_func()-my _ func 在哪里定义的?)

在所有情况下,你 可以只是做 import modulename,然后做 modulename.subthing1.subthing2.method("test")..。

from x import y as z的东西纯粹是为了方便-使用它,无论何时它将使您的代码更容易阅读或编写!

其他人已经涵盖了这里的大部分领域,但我只是想添加一个案例,我将使用 import X as Y(暂时) ,当我试验一个类或模块的新版本。

因此,如果我们正在迁移到一个模块的新实现,但是不想一次性删除所有的代码,我们可以编写一个 xyz_new模块,并在我们已经迁移的源文件中执行:

import xyz_new as xyz

然后,一旦我们切换了整个代码库,我们只需将 xyz模块替换为 xyz_new,并将所有导入恢复为

import xyz

不要这样做:

from X import *

除非您完全确定将使用该模块中的每个内容。即便如此,您也应该重新考虑使用不同的方法。

除此之外,只是风格问题。

from X import Y

是好的,并节省你很多打字。当我经常在其中使用某些内容时,我倾向于使用它。但是如果你从那个模块导入了很多内容,你可能会得到一个导入语句,看起来像这样:

from X import A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P

你明白我的意思吧,这时候进口就像

import X

或者如果我没有经常使用 X 中的任何东西。

让我在 django-dev 邮件列表中粘贴一段由吉多·范罗苏姆启动的对话:

[...] 例如,它是 Google Python 样式指南[1]的一部分 导入必须导入一个模块,而不是从该模块导入类或函数 类和函数的数量远远超过 模块,所以回忆一个特定的东西从哪里来是很重要的 如果以模块名称作为前缀,就更容易了。通常是多个模块 碰巧用同样的名字来定义事物——所以代码的读者 不必回到文件的顶部才能看到 模块导入给定的名称。

资料来源: http://groups.google.com/group/django-developers/view _ thread/thread/78975372cdfb7d1a”rel = “ noReferrer”> http://groups.google.com/group/django-developers/browse_thread/thread/78975372cdfb7d1a

1: http://code.google.com/p/soc/wiki/PythonStyleGuide#Module_and_package_imports

当您有一个编写良好的库(有时在 python 中是这种情况)时,您应该只是导入它并将其用作它。编写良好的库往往具有自己的生命和语言,从而产生令人愉快的代码,在这种情况下很少引用库。当一个库编写得很好时,您不应该经常需要重命名或者其他任何东西。

import gat


node = gat.Node()
child = node.children()

有时候这样写是不可能的,或者你想从你导入的库中提取一些东西。

from gat import Node, SubNode


node = Node()
child = SubNode(node)

有时候,如果您的导入字符串溢出了80列,那么对于很多事情您都可以这样做,这是一个好主意:

from gat import (
Node, SubNode, TopNode, SuperNode, CoolNode,
PowerNode, UpNode
)

最好的策略是将所有这些导入都放在文件的顶部。最好是按字母顺序排列,首先是 import 语句,然后是 import 语句。

现在我告诉你为什么这是最好的会议。

Python 完全可以有一个自动导入,当无法从全局名称空间找到值时,可以从主导入查找值。但这不是个好主意。我简单解释一下原因。除了实现起来比简单的导入更复杂之外,程序员不会太多地考虑依赖关系,也不会找到从哪里导入东西的方法,而不仅仅是查看导入。

需要找出依赖性是人们讨厌“ from... import *”的原因之一。但是也存在一些需要这样做的坏例子,例如 opengl-wrappings。

因此,导入定义实际上对于定义程序的依赖关系是有价值的。这是你应该利用他们的方式。通过它们,你可以快速地检查一些奇怪的函数是从哪里导入的。

我同意杰森不吸毒的事实

from X import *

但在我的情况下(我不是一个专业的程序员,所以我的代码不符合编码风格太好) ,我通常在我的程序中做一个文件的所有常量,如程序版本,作者,错误消息和所有的东西,所以文件只是定义,然后我进行导入

from const import *

这节省了我很多时间。但它是唯一具有该导入的文件,因为该文件中的所有内容都只是变量声明。

在带有类和定义的文件中执行这种导入可能很有用,但是当您必须读取代码时,您需要花费大量时间来定位函数和类。

上面有人这么说

from X import A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P

相当于

import X

import X允许对 A-P 进行直接修改,而 from X import ...创建 A-P 的副本。对于 from X import A..P,如果变量被修改,则不会获得对它们的更新。如果您修改它们,那么您只修改您的副本,但是 X 确实知道您的修改。

如果 A-P 是函数,你不会知道其中的区别。