我对使用Python导入模块的多种方式感到有些困惑。
import X
import X as Y
from A import B
我一直在阅读有关作用域和名称空间的内容,但我想就什么是最佳策略,在哪种情况下以及为什么这样做提出一些实用的建议。是否应该在模块级别或方法/功能级别进行导入?在__init__.py
或模块代码本身?
我的问题并没有真正回答“Python packages - import by class, not file”,尽管它显然是相关的。
答案 0 :(得分:63)
在我们公司的生产代码中,我们尝试遵循以下规则。
我们将导入放在文件的开头,就在主文件的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
作为一般规则,我们不在方法内部进行导入 - 它们只是使代码更慢,更不易读。有些人可能会发现这是一种轻松解决循环导入问题的好方法,但更好的解决方案是代码重组。
答案 1 :(得分:34)
让我在Guido van Rossum开始的django-dev邮件列表上粘贴一部分对话:
[...] 例如,它是Google Python风格指南[1]的一部分 import必须从中导入模块,而不是类或函数 模块。有比这更多的类和功能 模块,所以回想一下特定的东西来自何处 如果它以模块名称为前缀,则更容易。通常是多个模块 碰巧定义具有相同名称的东西 - 所以代码的读者 不必回到文件的顶部来查看从哪个 模块将导入给定名称。
来源: http://groups.google.com/group/django-developers/browse_thread/thread/78975372cdfb7d1a
1:http://code.google.com/p/soc/wiki/PythonStyleGuide#Module_and_package_imports
答案 2 :(得分:12)
我通常会在模块级别使用import X
。如果您只需要模块中的单个对象,请使用from X import Y
。
仅在您遇到名称冲突的情况下才使用import X as Y
。
我只使用函数级别的导入来导入模块用作主模块时需要的东西,例如:
def main():
import sys
if len(sys.argv) > 1:
pass
HTH
答案 3 :(得分:9)
上面有人说过
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是功能,你就不会知道差异。
答案 4 :(得分:5)
其他人已经涵盖了大部分内容,但我只想添加一个案例,我将使用import X as Y
(暂时),当我尝试新版本的类或模块时。
因此,如果我们要迁移到模块的新实现,但又不想一次性删除所有代码库,我们可能会编写一个xyz_new
模块并在源文件中执行此操作我们已迁移:
import xyz_new as xyz
然后,一旦我们切换整个代码库,我们只需将xyz
模块替换为xyz_new
并将所有导入更改回
import xyz
答案 5 :(得分:3)
不要这样做:
from X import *
除非你绝对确定你将使用该模块中的每一件事。即便如此,你应该重新考虑使用不同的方法。
除此之外,这只是风格问题。
from X import Y
很好,可以为您节省大量的打字费用。当我在相当频繁地使用它时,我倾向于使用它但是如果你从该模块中导入很多东西,你最终可能会得到一个如下所示的import语句:
from X import A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P
你明白了。就像进口一样
import X
变得有用。无论是那个,还是我不经常在X中使用任何东西。
答案 6 :(得分:2)
我通常会尝试使用常规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
函数替换为my_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
这些东西纯粹是为了方便 - 只要它能让您的代码更容易阅读或写入,就可以使用它!
答案 7 :(得分:1)
如果你有一个编写良好的库,有时在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
)
最佳策略是将所有这些导入保留在文件的顶部。优先按字母顺序排序,首先导入-statements,然后从import -statements进行排序。
现在我告诉你为什么这是最好的惯例。
Python完全可以进行自动导入,当从全局命名空间找不到值时,可以从主导入中查找该值。但这不是一个好主意。我很快解释原因。除了简单导入实现起来更复杂之外,程序员不会那么多地考虑依赖性,并且从导入的位置找出应该以除了查看导入之外的其他方式来完成。
需要找出依赖性是人们讨厌“来自......进口*”的一个原因。但是你需要做一些不好的例子,比如opengl -wrappings。
因此,导入定义实际上很有价值,因为它定义了程序的依赖性。这是你应该如何利用它们的方式。从中他们可以快速检查从哪里导入一些奇怪的函数。
答案 8 :(得分:0)
如果你有相同模块/类的不同实现,import X as Y
很有用。
使用一些嵌套的try..import..except ImportError..import
,您可以隐藏代码中的实现。见lxml etree import example:
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")
答案 9 :(得分:0)
我和杰森在不使用
这一事实from X import *
但在我的情况下(我不是专家程序员,所以我的代码不能很好地满足编码风格)我通常在我的程序中执行一个包含程序版本,作者,错误消息等所有常量的文件那些东西,所以文件只是定义,然后我进行导入
from const import *
这节省了我很多时间。但它是唯一具有该导入的文件,因为该文件中的所有内容都只是变量声明。
在包含类和定义的文件中进行这种导入可能很有用,但是当您必须阅读该代码时,您需要花费大量时间来定位函数和类。