Python(和Django)最佳导入实践

21 投票
3 回答
18744 浏览
提问于 2025-04-15 15:49

在导入代码的各种方式中,有没有一些方式比其他方式更好呢?这个链接 http://effbot.org/zone/import-confusion.htm 简单地说,

from foo.bar import MyClass

在正常情况下,或者除非你知道自己在做什么,不推荐用这种方式来导入 MyClass。更好的方式应该是:

import foo.bar as foobaralias

然后在代码中,要使用 MyClass 时可以这样:

foobaralias.MyClass

总的来说,上面提到的链接似乎在说,通常来说,从一个模块中导入所有内容比只导入模块的一部分要好。

不过,我提到的那篇文章其实很旧了。

我还听说,在 Django 项目的上下文中,最好只导入你想用的类,而不是整个模块。有人说这种方式可以避免循环导入错误,或者至少让 Django 的导入系统不那么脆弱。有人指出,Django 自己的代码似乎更喜欢用 "from x import y" 而不是 "import x"。

假设我正在做的项目没有使用 __init__.py 的任何特殊功能……(我们所有的 __init__.py 文件都是空的),那么我应该偏向使用哪种导入方法,为什么呢?

3 个回答

2

后者的好处在于,MyClass 的来源更加明确。前者把 MyClass 放在当前的命名空间里,这样代码就可以直接使用 MyClass,而不需要加上其他的前缀。所以,对于阅读代码的人来说,MyClass 的定义位置就不那么明显了。

13

首先,关于导入的一个重要规则:绝对不要使用 from foo import *

这篇文章在讨论循环导入的问题,这在结构不好的代码中仍然存在。我不喜欢循环导入;它的出现通常意味着某个模块的功能过于复杂,需要拆分。如果因为某种原因你必须处理包含循环导入的代码,而这些代码又无法重新安排,那么 import foo 是唯一的选择。

在大多数情况下,import foofrom foo import MyClass 之间没有太大区别。我更喜欢第二种方式,因为输入的内容更少,但有几个原因让我可能会选择第一种:

  • 模块和类/值的名字不一样。当导入的值的名字和模块没有关系时,读者可能会很难记住这个导入是来自哪里。

    • 好的例子: import myapp.utils as utils; utils.frobnicate()
    • 好的例子: import myapp.utils as U; U.frobnicate()
    • 不好的例子: from myapp.utils import frobnicate
  • 你从一个模块导入了很多值。为了省事,也为了让读者更容易阅读。

    • 不好的例子: from myapp.utils import frobnicate, foo, bar, baz, MyClass, SomeOtherClass, # yada yada
6

对我来说,这要看具体情况。如果你要用的方法或类名字很特别(比如,不是像 process() 这种常见名字),而且你会用得非常频繁,那就省省打字,直接用 from foo import MyClass 吧。

如果你要从一个模块里导入很多东西,可能更好的是直接导入整个模块,然后用 module.bar, module.foo, module.baz 这样的方式,这样可以保持命名空间的整洁。

你还提到过

有人说这种方式可以帮助避免循环导入错误,或者至少让 Django 的导入系统不那么脆弱。有人指出,Django 自己的代码似乎更喜欢用 "from x import y" 而不是 "import x"。

我不太明白这两种方式怎么能帮助避免循环导入。原因是,即使你用 from x import y,其实 x 的所有内容都会被导入。只有 y 会被引入到当前的命名空间,但整个模块 x 还是会被处理。你可以试试这个例子:

在 test.py 里,放入以下内容:

def a():
    print "a"

print "hi"

def b():
    print "b"

print "bye"

然后在 'runme.py' 里,放入:

from test import b

b()

然后就运行 python runme.py

你会看到以下输出:

hi
bye
b

所以即使你只导入了 b,test.py 里的所有内容还是被执行了。

撰写回答