我习惯了Java模型,其中每个文件可以有一个公共类。Python没有这个限制,我想知道组织类的最佳实践是什么。


当前回答

由于没有人为的限制,它实际上取决于什么是可理解的。如果你有一堆逻辑上分组在一起的相当短、简单的类,那就把它们扔进去。如果你有大、复杂的类,或者作为一个组没有意义的类,每个类一个文件。或者选择介于两者之间的东西。随着事情的变化而重构。

其他回答

这完全取决于项目有多大,类有多长,是否将从其他文件中使用它们等等。

例如,我经常使用一系列的类来进行数据抽象——所以我可能有4或5个类,它们可能只有1行长(类SomeData: pass)。

将它们分开到单独的文件中是愚蠢的——但由于它们可能从不同的文件中使用,将所有这些放在单独的data_model.py文件中是有意义的,所以我可以从mypackage中进行。data_model导入SomeData, someesubdata

如果您有一个包含大量代码的类,其中可能只有一些它使用的函数,那么将这个类和辅助函数分离到一个单独的文件中将是一个好主意。

你应该从mypackage.database.schema导入MyModel,而不是从mypackage.email.errors导入MyDatabaseModel——如果你从哪里导入东西是有意义的,并且文件不是数万行长,那么你已经正确地组织了它。

Python Modules文档中有一些关于组织包的有用信息。

Python文件被称为“模块”,它是组织软件的一种方式,使其“有意义”。另一个是目录,称为“包”。

模块是一个不同的东西,它可能有一个或二十几个密切相关的类。关键在于模块是你要导入的东西,你需要导入的模块对那些阅读、维护和扩展你的软件的人来说是完全合理的。

规则是这样的:模块是重用的单元。

不能轻易重用单个类。您应该能够毫无困难地重用模块。库中的所有内容(以及下载和添加的所有内容)都是模块或模块包。

例如,你正在做一些读取电子表格、进行一些计算并将结果加载到数据库的工作。你希望你的主程序看起来像什么?

from ssReader import Reader
from theCalcs import ACalc, AnotherCalc
from theDB import Loader

def main( sourceFileName ):
    rdr= Reader( sourceFileName )
    c1= ACalc( options )
    c2= AnotherCalc( options )
    ldr= Loader( parameters )
    for myObj in rdr.readAll():
        c1.thisOp( myObj )
        c2.thatOp( myObj )
        ldr.laod( myObj )

将导入看作是将代码组织成概念或块的方法。每个导入中究竟有多少类并不重要。重要的是用import语句描述的整体组织。

由于没有人为的限制,它实际上取决于什么是可理解的。如果你有一堆逻辑上分组在一起的相当短、简单的类,那就把它们扔进去。如果你有大、复杂的类,或者作为一个组没有意义的类,每个类一个文件。或者选择介于两者之间的东西。随着事情的变化而重构。

我碰巧喜欢Java模型,原因如下。将每个类放在单独的文件中,可以在浏览源代码时更容易看到类,从而促进重用。如果您将一堆类分组到一个文件中,其他开发人员可能不会很明显地发现其中有一些类可以通过浏览项目的目录结构来重用。因此,如果您认为您的类可能被重用,我将把它放在自己的文件中。

当我对庞大的文件感到恼火时,当理想的关联结构开始自然出现时,我发现自己把东西分开了。通常这两个阶段似乎是同时发生的。

如果你过早地将事情分开,这可能会非常烦人,因为你开始意识到需要完全不同的结构顺序。

另一方面,当任何.java或.py文件超过700行时,我开始不断地试图记住“那个特定的位”在哪里。

对于Python/Jython, import语句的循环依赖关系似乎也发挥了作用:如果你试图将太多合作的基本构建块分割到单独的文件中,这种语言的“限制”/“不完善”似乎迫使你将事物分组,也许是一种相当明智的方式。

至于分解成包,我真的不知道,但我想说可能同样的烦恼规则和快乐结构的出现适用于所有级别的模块化。