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


72

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

import X
import X as Y
from A import B

我一直在阅读有关范围和名称空间的信息,但是我想获得关于什么是最佳策略,在什么情况下以及为什么使用的最佳实践建议。导入应该在模块级别还是方法/功能级别进行?在__init__.py或模块代码本身中?

尽管“ Python软件包-按类而不是文件导入”确实没有回答我的问题尽管它显然是相关的。



Answers:


67

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

我们将导入文件放置在文件的开头,紧随主文件的文档字符串之后,例如:

"""
Registry related functionality.
"""
import wx
# ...

现在,如果我们导入的类是导入模块中为数不多的类之一,则可以直接导入名称,因此在代码中,我们仅需使用最后一部分,例如:

from RegistryController import RegistryController
from ui.windows.lists import ListCtrl, DynamicListCtrl

但是,有些模块包含数十个类,例如所有可能异常的列表。然后,我们导入模块本身,并在代码中对其进行引用:

from main.core import Exceptions
# ...
raise Exceptions.FileNotFound()

We use the import X as Y as rarely as possible, because it makes searching for usage of a particular module or class difficult. Sometimes, however, you have to use it if you wish to import two classes that have the same name, but exist in different modules, e.g.:

from Queue import Queue
from main.core.MessageQueue import Queue as MessageQueue

As a general rule, we don't do imports inside methods -- they simply make code slower and less readable. Some may find this a good way to easily resolve cyclic imports problem, but a better solution is code reorganization.


5
"they simply make code slower" is not that true. It has been tested here: stackoverflow.com/a/4789963/617185
kmonsoor

37

Let me just paste a part of conversation on django-dev mailing list started by Guido van Rossum:

[...] 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.

Source: http://groups.google.com/group/django-developers/browse_thread/thread/78975372cdfb7d1a

1: http://code.google.com/p/soc/wiki/PythonStyleGuide#Module_and_package_imports


IMO this should be the preferred way to go about importing things, especially in large projects.
Priidu Neemre

12

I would normally use import X on module level. If you only need a single object from a module, use from X import Y.

Only use import X as Y in case you're otherwise confronted with a name clash.

I only use imports on function level to import stuff I need when the module is used as the main module, like:

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

HTH


10

Someone above said that

from X import A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P

is equivalent to

import X

import X allows direct modifications to A-P, while from X import ... creates copies of A-P. For from X import A..P you do not get updates to variables if they are modified. If you modify them, you only modify your copy, but X does know about your modifications.

If A-P are functions, you won't know the difference.


In particular, if you want to use mock in unit tests to mock out say X.A, then that only works if you used import X.
RemcoGerlich

5

Others have covered most of the ground here but I just wanted to add one case where I will use import X as Y (temporarily), when I'm trying out a new version of a class or module.

So if we were migrating to a new implementation of a module, but didn't want to cut the code base over all at one time, we might write a xyz_new module and do this in the source files that we had migrated:

import xyz_new as xyz

Then, once we cut over the entire code base, we'd just replace the xyz module with xyz_new and change all of the imports back to

import xyz

3

DON'T do this:

from X import *

unless you are absolutely sure that you will use each and every thing in that module. And even then, you should probably reconsider using a different approach.

Other than that, it's just a matter of style.

from X import Y

is good and saves you lots of typing. I tend to use that when I'm using something in it fairly frequently But if you're importing a lot from that module, you could end up with an import statement that looks like this:

from X import A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P

You get the idea. That's when imports like

import X

become useful. Either that or if I'm not really using anything in X very frequently.


'from X import *' does have its uses -- e.g. with pyparsing.
John Fouhy

I agree. But in general, it's not a good habit to get into. Nothing annoys me more than having to track down what function came from what module because there are a lot of from x import * type statements.
Jason Baker

2

I generally try to use the regular import modulename, unless the module name is long, or used often..

For example, I would do..

from BeautifulSoup import BeautifulStoneSoup as BSS

..so I can do soup = BSS(html) instead of BeautifulSoup.BeautifulStoneSoup(html)

Or..

from xmpp import XmppClientBase

..instead of importing the entire of xmpp when I only use the XmppClientBase

Using import x as y is handy if you want to import either very long method names , or to prevent clobbering an existing import/variable/class/method (something you should try to avoid completely, but it's not always possible)

Say I want to run a main() function from another script, but I already have a main() function..

from my_other_module import main as other_module_main

..wouldn't replace my main function with my_other_module's main

Oh, one thing - don't do from x import * - it makes your code very hard to understand, as you cannot easily see where a method came from (from x import *; from y import *; my_func() - where is my_func defined?)

In all cases, you could just do import modulename and then do modulename.subthing1.subthing2.method("test")...

The from x import y as z stuff is purely for convenience - use it whenever it'll make your code easier to read or write!


2
IMHO, there are some misconceptions here... 1) "importing the entire of xmpp when I only use...": this falsely implies that this approach is "lighter", but Python will load and init the entire module anyway, regardless of how many objects you imported. As for "namespace pollution", both will add a single entry to local namespace: xmpp or XmppClientBase. So this rationale is not valid
MestreLion

2
2) "as you cannot easily see where a method came from": True for * imports, but also true for your approach of using as just to shorten a module/object name. Where does BSS() come from? Using from also suffers (a bit) of this: from mymod import MyClass. Now 300 lines ahead you see class MyOtherClass(MyClass):... now, where did MyClass came from again? A reader is forced to always go back to the header to see check where which object was imported from
MestreLion

1

When you have a well-written library, which is sometimes case in python, you ought just import it and use it as it. Well-written library tends to take life and language of its own, resulting in pleasant-to-read -code, where you rarely reference the library. When a library is well-written, you ought not need renaming or anything else too often.

import gat

node = gat.Node()
child = node.children()

Sometimes it's not possible to write it this way, or then you want to lift down things from library you imported.

from gat import Node, SubNode

node = Node()
child = SubNode(node)

Sometimes you do this for lot of things, if your import string overflows 80 columns, It's good idea to do this:

from gat import (
    Node, SubNode, TopNode, SuperNode, CoolNode,
    PowerNode, UpNode
)

The best strategy is to keep all of these imports on the top of the file. Preferrably ordered alphabetically, import -statements first, then from import -statements.

Now I tell you why this is the best convention.

Python could perfectly have had an automatic import, which'd look from the main imports for the value when it can't be found from global namespace. But this is not a good idea. I explain shortly why. Aside it being more complicated to implement than simple import, programmers wouldn't be so much thinking about the depedencies and finding out from where you imported things ought be done some other way than just looking into imports.

Need to find out depedencies is one reason why people hate "from ... import *". Some bad examples where you need to do this exist though, for example opengl -wrappings.

So the import definitions are actually valuable as defining the depedencies of the program. It is the way how you should exploit them. From them you can quickly just check where some weird function is imported from.


0

The import X as Y is useful if you have different implementations of the same module/class.

With some nested try..import..except ImportError..imports you can hide the implementation from your code. See 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")

0

I'm with Jason in the fact of not using

from X import *

But in my case (i'm not an expert programmer, so my code does not meet the coding style too well) I usually do in my programs a file with all the constants like program version, authors, error messages and all that stuff, so the file are just definitions, then I make the import

from const import *

That saves me a lot of time. But it's the only file that has that import, and it's because all inside that file are just variable declarations.

Doing that kind of import in a file with classes and definitions might be useful, but when you have to read that code you spend lots of time locating functions and classes.

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.