代码之家  ›  专栏  ›  技术社区  ›  Simon

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

  •  70
  • Simon  · 技术社区  · 17 年前

    我有点困惑,您可以通过多种方式在Python中导入模块。

    import X
    import X as Y
    from A import B
    

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

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

    10 回复  |  直到 10 年前
        1
  •  63
  •   Dzinx    17 年前

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

    我们将导入放在文件的开头,就在主文件的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
    

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

        2
  •  34
  •   ravi404 Reza    11 年前

    让我把对话的一部分粘贴到guido van rossum开始的django dev邮件列表上:

    […] 例如,它是谷歌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

        3
  •  12
  •   MvdD    17 年前

    我通常会用 import X 在模块级。如果只需要模块中的单个对象,请使用 from X import Y .

    只使用 import X as Y 以防你遇到名字冲突。

    当模块用作主模块时,我只使用功能级别的导入来导入所需的内容,例如:

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

    高温高压

        4
  •  8
  •   dragonloverlord Robert Jacobs    10 年前

    上面有人说

    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是函数,你就不知道有什么区别。

        5
  •  5
  •   davidavr    17 年前

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

    因此,如果我们迁移到一个模块的新实现中,但不想一次全部削减代码库,我们可能会编写一个 xyz_new 模块化,并在迁移的源文件中执行此操作:

    import xyz_new as xyz
    

    然后,一旦我们切断了整个代码库,我们只需替换 xyz 模块与 Xyz新 把所有进口商品都改回

    import xyz
    
        6
  •  3
  •   Jason Baker    17 年前

    不要这样做:

    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中的任何东西。

        7
  •  2
  •   dbr    17 年前

    我一般都试着用普通的 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 与我的其他模块一起工作 主要的

    哦,有一件事-不要做 from x import * -它使您的代码很难理解,因为您不容易看到方法的来源。( from x import *; from y import *; my_func() -我的“func”定义在哪里?

    在任何情况下,你 能够 只要做 导入模块名 然后做 modulename.subthing1.subthing2.method("test")

    这个 from x import y as z 这些东西纯粹是为了方便——只要能让代码更容易读写,就可以使用它!

        8
  •  1
  •   Diodeus - James MacFarlane    16 年前

    当您有一个编写良好的库(在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
    )
    

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

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

    python完全可以有一个自动导入,当在全局命名空间中找不到该值时,可以从主导入中查找该值。但这不是个好主意。我很快解释了原因。除了实现比简单的导入更复杂之外,程序员不会太多地考虑依赖性,并且发现从哪里导入东西应该以其他方式进行,而不仅仅是查看导入。

    需要找出出处是人们讨厌“来自……的原因之一。导入*”。但也有一些不好的例子需要这样做,例如OpenGL包装。

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

        9
  •  0
  •   olt    17 年前

    这个 import X as Y 如果同一模块/类有不同的实现,则非常有用。

    有一些嵌套的 try..import..except ImportError..import s您可以从代码中隐藏实现。见 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")
    
        10
  •  0
  •   CastleDweller    15 年前

    我和杰森在一起的事实是不使用

    from X import *
    

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

    from const import *
    

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

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

    推荐文章