我对在 Python 中导入模块的多种方式感到有些困惑。
import X
import X as Y
from A import B
我一直在阅读有关范围和名称空间的信息,但我想就什么是最佳策略、在什么情况下以及为什么要提供一些实用的建议。导入应该发生在模块级别还是方法/函数级别?在__init__.py
模块代码本身中还是在模块代码中?
“ Python 包 - 按类导入,而不是文件”并没有真正回答我的问题,尽管它显然是相关的。
我对在 Python 中导入模块的多种方式感到有些困惑。
import X
import X as Y
from A import B
我一直在阅读有关范围和名称空间的信息,但我想就什么是最佳策略、在什么情况下以及为什么要提供一些实用的建议。导入应该发生在模块级别还是方法/函数级别?在__init__.py
模块代码本身中还是在模块代码中?
“ Python 包 - 按类导入,而不是文件”并没有真正回答我的问题,尽管它显然是相关的。
在我们公司的生产代码中,我们尽量遵循以下规则。
我们将导入放在文件的开头,就在主文件的文档字符串之后,例如:
"""
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
作为一般规则,我们不在方法内部进行导入——它们只会使代码变慢且可读性降低。有些人可能会发现这是轻松解决循环导入问题的好方法,但更好的解决方案是代码重组。
让我将部分对话粘贴到由 Guido van Rossum 发起的 django-dev 邮件列表中:
[...] 例如,Google Python 风格指南 [1] 的一部分是所有导入都必须导入一个模块,而不是来自该模块的类或函数。类和函数比模块多得多,因此如果以模块名称为前缀,则回忆特定事物的来源要容易得多。通常多个模块碰巧定义了具有相同名称的事物——因此代码的读者不必回到文件顶部来查看给定名称是从哪个模块导入的。
来源: http ://groups.google.com/group/django-developers/browse_thread/thread/78975372cdfb7d1a
1:http ://code.google.com/p/soc/wiki/PythonStyleGuide#Module_and_package_imports
我通常会import X
在模块级别使用。如果您只需要模块中的单个对象,请使用from X import Y
.
仅import X as Y
在您遇到名称冲突的情况下使用。
当模块用作主模块时,我只在功能级别使用导入来导入我需要的东西,例如:
def main():
import sys
if len(sys.argv) > 1:
pass
高温高压
上面有人说
from X import A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P
相当于
import X
import X
允许直接修改 AP,同时from X import ...
创建 AP 的副本。因为from X import A..P
如果变量被修改,你不会得到更新。如果您修改它们,您只修改您的副本,但 X 确实知道您的修改。
如果AP是函数,你就不会知道区别。
其他人已经涵盖了这里的大部分内容,但我只想添加一个案例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 中使用任何东西。
我一般会尝试使用常规的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
..不会用 my_other_module 替换我的main
函数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
东西纯粹是为了方便——只要它能让你的代码更容易阅读或编写,就使用它!
当你有一个编写良好的库时,有时在 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 -statements,然后是 from import -statements。
现在我告诉你为什么这是最好的约定。
Python 完全可以有一个自动导入,当无法从全局命名空间中找到它时,它会从主导入中查找值。但这不是一个好主意。我简要解释一下原因。除了实现起来比简单的导入更复杂之外,程序员不会过多地考虑依赖关系并找出从哪里导入的东西应该以其他方式完成,而不仅仅是查看导入。
需要找出依赖关系是人们讨厌“from ... import *”的原因之一。但是,您需要执行此操作的一些不好的示例存在,例如 opengl -wrappings。
因此,导入定义实际上对于定义程序的依赖关系很有价值。这是你应该如何利用它们的方式。从他们那里你可以快速检查一些奇怪的功能是从哪里导入的。
如果您有相同模块/类的不同实现,这import X as Y
很有用。
使用一些嵌套try..import..except ImportError..import
的 s,您可以从代码中隐藏实现。请参阅lxml etree 导入示例:
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")
事实上,我和杰森在一起不使用
from X import *
但就我而言(我不是专业程序员,所以我的代码不太符合编码风格)我通常在我的程序中创建一个包含所有常量的文件,如程序版本、作者、错误消息和所有这些东西,所以文件只是定义,然后我进行导入
from const import *
这节省了我很多时间。但它是唯一具有该导入的文件,这是因为该文件中的所有内容都只是变量声明。
在包含类和定义的文件中进行这种导入可能很有用,但是当您必须阅读该代码时,您会花费大量时间来定位函数和类。