我如何在Python中设计一个类?
我之前在处理检测狗爪和爪子里的脚趾的问题时得到了很多很棒的帮助,但这些解决方案只能一次处理一个测量值。
现在我有一些数据,具体包括:
- 大约30只狗;
- 每只狗有24个测量值(分成几个小组);
- 每个测量值至少有4个接触点(每只爪子一个)并且
- 每个接触点又分成5个部分,
- 还有几个参数,比如接触时间、位置、总力量等等。
显然,把所有东西都放进一个大对象里是行不通的,所以我觉得需要用类来替代现在的那些函数。尽管我读过《学习Python》关于类的章节,但我还是无法把它应用到自己的代码中(GitHub链接)。
我还觉得每次想获取一些信息时都处理所有数据有点奇怪。一旦我知道了每只爪子的位置,就没必要再计算一次。此外,我想比较同一只狗的所有爪子,以确定哪个接触点属于哪只爪子(前爪/后爪,左爪/右爪)。如果我继续只用函数,这会变得很麻烦。
所以现在我在寻找建议,想知道如何创建类,以便以合理的方式处理我的数据(一只狗的数据压缩包链接)。
6 个回答
我喜欢TDD(测试驱动开发)的方法……
首先,先写下你希望程序表现出来的功能测试。然后再写代码让这些测试通过。这个阶段不要太担心代码的设计,先确保有一套测试和能通过的程序就行。即使最后你写出来的代码是一大堆复杂的东西,也没关系。
有时候,在这个初始过程中,你会发现某些功能很难测试,这时候就需要把它拆分开来,以便于测试。这可能说明你需要创建一个新的类来处理这部分功能。
接下来就是有趣的部分……重构。在你有了能正常工作的程序后,你就能看到那些复杂的部分。通常一些小的功能会变得明显,这可能会提示你需要一个新类。如果没有,那就找找有没有办法简化代码。提取出服务对象和数值对象,简化你的方法。
如果你正确使用git(你有在用git吧?),你可以在重构时快速尝试一些拆分的方式,如果发现不简化,随时可以放弃并恢复到之前的状态。
通过先写经过测试的工作代码,你会对问题领域有更深入的理解,这种理解是设计优先的方法所无法轻易获得的。写测试和代码可以帮助你克服“我该从哪里开始”的困惑。
以下建议(类似于 @S.Lott 的建议)来自书籍 《Python入门:从新手到专业人士》
先把你的问题写下来(这个问题应该解决什么?)。把所有的名词、动词和形容词都划线。
看看名词,找出可能的类。
看看动词,找出可能的方法。
看看形容词,找出可能的属性。
把方法和属性分配给你的类。
为了进一步完善类,这本书还建议我们可以这样做:
写下(或想象出)一组 使用案例——你的程序可能如何被使用的场景。尽量覆盖所有功能。
逐步思考每个使用案例,确保我们需要的内容都被考虑到。
如何设计一个类。
先把想法写下来。你已经开始这样做了。有些人不这么做,结果就会遇到问题。
把你的想法扩展成简单的语句,说明这些对象要做什么。也就是说,写下你要对这些东西进行的各种计算。你列出的30只狗、24个测量值、4个联系人,以及每个联系人有几个“参数”,这些都很有意思,但只是故事的一部分。接下来要考虑的是“每只狗的每只爪子的位置信息”和“比较同一只狗的所有爪子,以确定哪个联系人属于哪个爪子”,这才是对象设计的下一步。
把名词画个下划线。真的。有些人对此有不同看法,但我发现对于第一次接触面向对象开发的人来说,这很有帮助。把名词画下划线。
回顾这些名词。像“参数”和“测量”这样的通用名词需要替换成具体的、与你的问题相关的名词。具体的内容能帮助你更清楚地理解问题,而通用名词则会模糊细节。
对于每个名词(比如“联系人”、“爪子”、“狗”等),写下这个名词的属性和这个对象要进行的操作。不要省略这一步。每一个属性都要写下来。例如,“数据集包含30只狗”这一点很重要。
对于每个属性,确定它是与某个定义好的名词的关系,还是某种“原始”或“基本”的数据,比如字符串、浮点数或其他不可再分的数据。
对于每个操作或行为,你需要确定哪个名词负责,哪个名词只是参与。这里涉及到“可变性”的问题。有些对象会被更新,有些则不会。可变对象必须对它们的变化负责。
到这个阶段,你可以开始把名词转化为类的定义。一些集合名词可以是列表、字典、元组、集合或命名元组,这些你不需要做太多工作。其他类则更复杂,可能是因为复杂的派生数据,或者因为需要进行某种更新或变更。
别忘了用unittest单独测试每个类。
另外,没有规定类必须是可变的。比如在你的情况下,几乎没有可变的数据。你拥有的是通过转换函数从源数据集中创建的派生数据。