What are good rules of thumb for Python imports?
我有点困惑,您可以通过多种方式在Python中导入模块。
1 2 3 | import X import X as Y from A import B |
我一直在阅读范围界定和名称空间的相关内容,但我希望得到一些关于什么是最佳策略、在什么情况下以及为什么是最佳策略的实用建议。导入应该发生在模块级别还是方法/函数级别?在
我的问题并没有得到"python包——按类导入,而不是文件导入"的真正回答,尽管它显然是相关的。
在我们公司的生产代码中,我们试图遵循以下规则。
我们将导入放在文件的开头,就在主文件的docstring之后,例如:
1 2 3 4 5 | """ Registry related functionality. """ import wx # ... |
号
现在,如果导入的类是导入模块中为数不多的类之一,那么我们直接导入名称,这样在代码中我们只需要使用最后一部分,例如:
1 2 | from RegistryController import RegistryController from ui.windows.lists import ListCtrl, DynamicListCtrl |
但是,有些模块包含几十个类,例如所有可能的异常列表。然后我们导入模块本身并在代码中引用它:
1 2 3 | from main.core import Exceptions # ... raise Exceptions.FileNotFound() |
。
我们很少使用
1 2 | from Queue import Queue from main.core.MessageQueue import Queue as MessageQueue |
作为一般规则,我们不在方法内部进行导入——它们只是使代码更慢和更不可读。有些人可能会发现这是一个很容易解决循环导入问题的好方法,但更好的解决方案是代码重组。
让我把对话的一部分粘贴到guido van rossum开始的django dev邮件列表上:
[...]
For example, it's part of the Google Python style guides[1] that all
imports must import a module, not a class or function from that
module. There are way more classes and functions than there are
modules, so recalling where a particular thing comes from is much
easier if it is prefixed with a module name. Often multiple modules
happen to define things with the same name -- so a reader of the code
doesn't have to go back to the top of the file to see from which
module a given name is imported.
号
资料来源:http://groups.google.com/group/django-developers/browse-thread/thread/78975372cdfb7d1a
1:http://code.google.com/p/soc/wiki/pythonstyleguide module_and_package_导入
我通常在模块级使用
只有在遇到名字冲突时才使用
当模块用作主模块时,我只使用功能级别的导入来导入所需的内容,例如:
1 2 3 4 | def main(): import sys if len(sys.argv) > 1: pass |
高温高压
上面有人说
1 | from X import A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P |
。
等于
1 | import X |
。
如果a-p是函数,你就不知道有什么区别。
其他的已经覆盖了这里的大部分内容,但我只是想添加一个案例,在我尝试类或模块的新版本时,我将使用EDOCX1(临时)。
因此,如果我们迁移到一个模块的新实现中,但不想一次性全部削减代码库,我们可以编写一个
1 | import xyz_new as xyz |
然后,一旦我们切断了整个代码库,我们只需将
1 | import xyz |
。
不要这样做:
1 | from X import * |
号
除非你绝对确信你将使用该模块中的每一件事。即使如此,你也应该重新考虑使用不同的方法。
除此之外,这只是一个风格问题。
1 | from X import Y |
号
很好,可以节省大量的打字时间。当我经常在其中使用某些内容时,我倾向于使用它,但是如果您从该模块中导入了大量内容,则最终可能会得到如下的导入语句:
1 | from X import A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P |
号
你明白了。那时候进口就像
1 | import X |
号
变得有用。或者如果我不经常使用x中的任何东西。
我通常尝试使用常规的
例如,我会……
1 | from BeautifulSoup import BeautifulStoneSoup as BSS |
。
所以我可以用
或…
1 | from xmpp import XmppClientBase |
…而不是在我只使用xmppclientbase时导入整个xmpp
如果您想导入非常长的方法名,或者为了防止破坏现有的导入/变量/类/方法(您应该尝试完全避免这种情况,但并不总是可能的),使用
假设我想从另一个脚本运行一个main()函数,但我已经有了一个main()函数。
1 | from my_other_module import main as other_module_main |
。
…不会用我的其他模块的
哦,有一件事——不要做
在所有情况下,你可以先做
当您有一个编写良好的库(在Python中有时是这样)时,您应该导入它并将其作为它使用。写得好的图书馆往往会占用它自己的生命和语言,导致令人愉快的阅读代码,在那里你很少参考图书馆。当一个图书馆写得很好的时候,你不应该太频繁地需要重新命名或者其他任何东西。
1 2 3 4 | import gat node = gat.Node() child = node.children() |
有时不可能这样写,或者你想从你导入的库中提取东西。
1 2 3 4 | from gat import Node, SubNode node = Node() child = SubNode(node) |
号
有时,对于很多事情都要这样做,如果导入字符串溢出80列,最好这样做:
1 2 3 4 | from gat import ( Node, SubNode, TopNode, SuperNode, CoolNode, PowerNode, UpNode ) |
最好的策略是将所有这些导入保持在文件的顶部。最好按字母顺序排列,先导入-语句,然后从导入-语句。
现在我告诉你为什么这是最好的会议。
python完全可以有一个自动导入,当在全局命名空间中找不到该值时,可以从主导入中查找该值。但这不是个好主意。我很快解释了原因。除了实现比简单的导入更复杂之外,程序员不会太多地考虑依赖性,并且发现从哪里导入东西应该以其他方式进行,而不仅仅是查看导入。
需要找出出处是人们讨厌"来自……的原因之一。导入*"。但也存在一些需要这样做的坏例子,例如OpenGL包装。
因此,导入定义实际上对于定义程序的依赖性很有价值。这就是你应该如何利用它们的方式。从它们中,您可以快速地检查一些奇怪的函数是从哪里导入的。
我和杰森在一起的事实是不使用
1 | from X import * |
。
但是在我的例子中(我不是一个专业的程序员,所以我的代码不太符合编码风格),我通常在我的程序中做一个包含所有常量的文件,比如程序版本、作者、错误消息和所有这些东西,所以文件只是定义,然后我进行导入
1 | from const import * |
这节省了我很多时间。但它是唯一一个有这个导入的文件,这是因为该文件中的所有内容都只是变量声明。
在包含类和定义的文件中执行这种导入可能很有用,但是当您必须读取该代码时,需要花费大量时间来定位函数和类。
如果您对同一个模块/类有不同的实现,那么
使用一些嵌套的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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") |
。