对于泛型抽象类,使用包的__init__.py模块是pythonic吗?

时间:2014-06-17 14:21:14

标签: python python-3.x abstract-class declaration

我正在根据python3中的面向对象模型为我的公司开发一个相当复杂的应用程序。该应用程序包含几个包和子包,每个包 - 当然 - 包含__init__.py模块。

我主要使用那些__init__.py模块为它们内部的包声明泛型类,这些类只用作它们各自包的抽象模板。

我现在的问题是:这是使用__init__.py模块的“好”/“正确”/“pythonic”方式吗?或者我宁愿在其他地方声明我的泛型类?

举一个例子,我们假设一个包mypkg

mypkg.__init__.py

class Foo(object):
    __some_attr = None

    def __init__(self, some_attr):
        self.__some_attr = some_attr

    @property
    def some_attr(self):
        return self.__some_attr

    @some_attr.setter
    def some_attr(self, val):
        self.__some_attr = val

mypkg.myfoo.py

from . import Foo

class MyFoo(Foo):
    def __init__(self):
        super().__init__("this is my implemented value")

    def printme(self):
        print(self.some_attr)

4 个答案:

答案 0 :(得分:4)

这取决于您要提供的API。例如,标准库中的collections模块定义了__init__.py 1 中的所有类。 无论这意味着什么,标准库应该是非常“pythonic”。

然而它主要提供“类似模块”的界面。很难看到:

import collections.abc

如果您已有子包,则可能更好地引入新的子包。 如果当前使用该包实际上并不依赖于子包,您可以考虑将代码放在__init__.py中。或者将代码放在一些私有模块中,只需导入__init__.py内的名称(这就是'所喜欢的)


如果你只关心放置抽象基类的最佳位置,如上所示(collections.abc包含collections包的抽象基类),你可以从中看到标准库的abc模块,定义包含它们的abc.py子模块是很常见的。 您可以考虑直接从__init__.py执行:

公开它们
from .abc import *
from . import abc

# ...
__all__ = list_of_names_to_export + abc.__all__

__init__.py内。


1 使用的实际实现是在C中:_collectionsmodule.c

答案 1 :(得分:3)

您始终可以将所有内容放入一个源文件中。将更复杂的代码拆分为单独的模块或包的原因是将相互关联的事物与不相关的事物分开。分开的东西应该尽可能独立于其余部分。它适用于任何级别:数据结构,函数,类,模块,包,应用程序。

在模块内部或包内应该应用相同的规则。我同意Bakuriu __init__.py应该与包基础结构密切相关,但不一定与模块的功能相关。我个人认为__init__.py应该尽可能简单。原因首先是一切都应该尽可能简单但不简单。其次,阅读包装代码的人倾向于这样思考。他们可能不期望__init__.py中的意外功能。为此目的,在包中创建generic.py可能会更好。更容易记录模块的用途(比如通过它的顶级文档字符串)。

分离从一开始就越好,将来可以更好地组合独立功能。您可以获得更好的灵活性 - 包括在包内使用模块以及将来的修改。

答案 2 :(得分:0)

确实可以将__init__.py用于特定模块初始化,但我从未见过有人使用它来定义新函数。我所知道的唯一“正确”用途是this subject ...中讨论的内容。

无论如何,由于您可能有一个复杂的应用程序,您可以使用一个临时文件来定义所有需要的函数,而不是直接在__init__.py模块中定义它们。这将使您更易于阅读,之后更容易更改。

答案 3 :(得分:-1)

除了定义__init__.py之外,不要 使用__all__。如果你能避免的话,你将挽救这么多生命。

原因:开发人员通常会查看软件包和模块。但是有时你会遇到一个问题。如果你有包,你可以假设它里面有一个模块和代码。但是你很少会将__init__.py视为一个,因为,让我们面对它,大多数情况下只需要从目录导入模块。

package
    __init__.py
    mod1.py
    humans.py
    cats.py
    dogs.py
    cars.py
    commons.py

应该在哪个班级Family?它是普通阶级,它取决于其他人,因为我们可以创造人类,狗和猫的家庭,甚至汽车!

根据我的逻辑和朋友的逻辑,它应该放在单独的文件中,但我会尝试在commons中找到它,然后在humans然后...我会尴尬,因为我不知道它在哪里!

愚蠢的例子,是吗?但它提出了一个观点。