在包

时间:2015-10-22 08:08:52

标签: python-3.x

我正在编写一个名为 Foo 的库作为示例。

__init__.py文件:

from .foo_exceptions import *
from .foo_loop import FooLoop()
main_loop = FooLoop()
from .foo_functions import *

__all__ = ['main_loop'] + foo_exceptions.__all__ + foo_functions.__all__

安装后,可以像这样使用:

# example A
from Foo import foo_create, main_loop

foo_obj = foo_create()
main_loop().register(foo_obj)

或者像这样:

# example B
import Foo

foo_obj = Foo.foo_create()
Foo.main_loop().register(foo_obj)

我显然更喜欢B方法。没有名称冲突,并且明确说明了每个外部对象的来源。

这么多介绍,现在我的问题。在这个库中,我需要从不同的文件中导入一些东西。同样,我有几种方法可以做到这一点。问题是哪种风格更喜欢 - C,D还是E?请阅读以下内容。

# example C
from . import foo_exceptions

raise foo_exceptions.FooError("fail")

# example D
from .foo_exceptions import FooError

raise FooError("fail")

# example E
from . import FooError

raise FooError("fail")

方法C的缺点是,导入整个模块而不是仅导入一些必需的对象会增加循环导入问题的可能性。还要考虑这一行:

from . import foo_exceptions, main_loop

它看起来像是从一个来源导入2个符号,但它不是。前者(foo_exceptions)是当前目录中的模块(.py文件),后者是__init__.py中定义的对象。

这就是为什么我没有使用C风格,而最终形式的问题是:D或E(以及为什么)?

(感谢您阅读这个长问题。所有代码片段仅为示例,可能包含拼写错误)

在alexanderlukanin的回答之后:

  • EDIT1:更正了init.py中的错误
  • 注1:foo_前缀仅用于强调对象之间的关系
  • EDIT2:导入的库接口的一部分时,样式E不可用。我认为我们有一个胜利者:它是from .module import symbol形式。

1 个答案:

答案 0 :(得分:0)

  1. 不要使用旧式relative imports

    # Import from foo/foo_loop.py
    # This DOES NOT WORK in Python 3
    # and MAY NOT WORK AS EXPECTED in Python 2
    from foo_loop import FooLoop
    
    # This is reliable and unambiguous
    from .foo_loop import FooLoop
    
  2. 除非确实必须使用星号导入,否则不要使用星号导入。

    # Namespace pollution! Name clashes!
    from .submodule import *
    
  3. 不要使用前缀 - 您已完全为此目的获得了名称空间。

    # Unpythonic
    from foo import foo_something_create
    foo_something_create()
    
    # Pythonic
    import foo.something
    foo.something.create()
    
  4. 您的软件包的API必须定义明确。你的实现不能太纠结。其余的是品味问题。

    # [C] This is good.
    # Import order: __init__.py, exceptions.py
    from . import exceptions
    raise exceptions.FooError
    
    # [D] This is also fine.
    # Import order is the same as above,
    # only name binding inside the current module is different.
    from .exceptions import FooError
    raise FooError
    
    # [E] This is not as good because it adds one unnecessary level of indirection
    # submodule.py -> __init__.py -> exceptions.py
    from . import FooError
    raise FooError
    
  5. 另请参阅:Circular (or cyclic) imports in Python