Python导入有哪些好的经验法则?

时间:2008-10-11 09:59:36

标签: python python-import

我对使用Python导入模块的多种方式感到有些困惑。

import X
import X as Y
from A import B

我一直在阅读有关作用域和名称空间的内容,但我想就什么是最佳策略,在哪种情况下以及为什么这样做提出一些实用的建议。是否应该在模块级别或方法/功能级别进行导入?在__init__.py或模块代码本身?

我的问题并没有真正回答“Python packages - import by class, not file”,尽管它显然是相关的。

10 个答案:

答案 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 *

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

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