如何编写良好/正确的__init__.py包文件


187

我的软件包具有以下结构:

mobilescouter/
    __init__.py #1
    mapper/
        __init__.py  #2
        lxml/
            __init__.py #3
            vehiclemapper.py
            vehiclefeaturemapper.py
            vehiclefeaturesetmapper.py
        ...
        basemapper.py
   vehicle/
        __init__.py #4
        vehicle.py
        vehiclefeature.py
        vehiclefeaturemapper.py
   ...

我不确定__init__.py应如何正确写入文件。
__init__.py #1样子:

__all__ = ['mapper', 'vehicle']
import mapper
import vehicle

但是例如应该__init__.py #2看起来如何?我的是:

__all__ = ['basemapper', 'lxml']
from basemaper import *
import lxml

什么时候应该__all__使用?


2
请注意,尽管在代码中使用import *通常是非常不好的做法,应尽可能避免使用。很少有很好的用例,但是确实很少。
Mayou36

PSA:如果您有兴趣学习如何编写优质的名称空间包(新型包),请查看以下示例包:github.com/pypa/sample-namespace-packages
Kyle

Answers:


145

__all__很好-它有助于指导导入语句,而无需自动导入模块 http://docs.python.org/tutorial/modules.html#importing-from-a-package

使用__all__import *是多余的,仅__all__需要

我认为import *__init__.py导入软件包中使用的最有力的理由之一是能够重构已经成长为多个脚本的脚本,而又不会破坏现有的应用程序。但是,如果您从一开始就设计一个包装。我认为最好将__init__.py文件留空。

例如:

foo.py - contains classes related to foo such as fooFactory, tallFoo, shortFoo

然后应用程序增长,现在是整个文件夹

foo/
    __init__.py
    foofactories.py
    tallFoos.py
    shortfoos.py
    mediumfoos.py
    santaslittlehelperfoo.py
    superawsomefoo.py
    anotherfoo.py

然后初始化脚本可以说

__all__ = ['foofactories', 'tallFoos', 'shortfoos', 'medumfoos',
           'santaslittlehelperfoo', 'superawsomefoo', 'anotherfoo']
# deprecated to keep older scripts who import this from breaking
from foo.foofactories import fooFactory
from foo.tallfoos import tallFoo
from foo.shortfoos import shortFoo

因此编写的用于执行以下操作的脚本在更改期间不会中断:

from foo import fooFactory, tallFoo, shortFoo

3
我对“ 全部 ”和逐行导入感到非常困惑。您的例子很有启发性。
Junchen

2
我迷茫了“ __all__import *是多余的”,__all__所使用的模块的消费者,并且from foo import *所使用的模块本身使用他人....
尼克牛逼

using __all__ and import * is redundant, only __all__ is needed 那些冗余如何?他们做不同的事情。
endolith

112

我自己的__init__.py文件经常为空。特别是,我从来没有加入from blah import *__init__.py-如果“导入包”意味着直接将各种类,函数等定义为包的一部分,那么我将以词法将其内容复制blah.py到包的内容中__init__.py并删除blah.py(源文件的乘法在这里没有好处)。

如果您确实坚持支持import *惯用语(eek),那么使用__all__(尽量减少使用姓名列表)可能会有助于控制损失。通常,名称空间和显式导入是一件好事,我强烈建议您重新考虑基于系统地绕过一个或两个概念的任何方法!


9
就我个人而言,我更喜欢将它们分开,然后导入*。原因是,尽管有很多折叠和东西,但我仍然讨厌浏览包含太多类的文件,即使它们相关。
Stefano Borini,2009年

5
@stefano考虑一个大框架。如果使用它,那么import *您必须无条件地接受所有框架,甚至是您永远不会使用的功能。保持__init__.py空给你的不仅仅是全有或全无的语义更多的机会。想想扭曲。
毫克

如果将其保留为空,即使在导入了mobilescouter之后,仍然无法使用mobilescouter.mapper或mobilescouter.vehicle或mobilescouter.what。导入mobilescouter.A,mobilescouter.B .....太冗长了吗?
sunqiang

6
@sunqiang这是个人的,但我不这么认为。from mobilescouter import A, B只是一行代码,您没有一个拥有666个类的项目,而每个项目都有自己的文件,对吗?如果您import *的代码中有两个或两个以上,则会在名称空间中填充潜在的垃圾,并且很快您会忘记其A来源。如果上层包装也这样做?您正在获取所有子程序包和子子程序包。就像zen的python所说,显式胜于隐式。
毫克

1
@mg,如果init .py文件中有一行“ import A,B” ,那么我可以使用以下语法调用A(或B):mobilescouter.A; 如果我们使用“ from mobilescouter import A,B”,那么它就是A.something。有时只是这一行,我不记得A是mobilescouter的子功能,并且我认为这会导致名称空间污染(尽管它比“ from mobilescouter import *”要好得多。我仍然更喜欢“ import pkgname”给用户统一的公共接口,所以init .py做import sub_pkgname的事情
sunqiang

1

你的 __init__.py应该有一个文档字符串

尽管所有功能都在模块和子程序包中实现,但您的程序包docstring是记录从何开始的地方。例如,考虑 python email软件包。软件包文档是介绍性的介绍,描述了目的,背景以及软件包中各个组件如何协同工作。如果您使用sphinx或其他软件包从文档字符串自动生成文档,则文档字符串正是描述此类介绍的正确位置。

有关其他任何内容,请参阅firecrowAlex Martelli的出色回答。


是否实际__init__.pyemail包装遵循这一指导方针?我看到一行docstring并不能解释“程序包中的各个组件如何协同工作”。
Gertlex

@Gertlex可能仅在Web文档中。
格里特
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.