如何在 Python 中设计一个类?

Posted

技术标签:

【中文标题】如何在 Python 中设计一个类?【英文标题】:How do I design a class in Python? 【发布时间】:2011-05-11 07:55:39 【问题描述】:

我以前的问题for detecting paws 和toes within a paw 得到了一些非常棒的帮助,但所有这些解决方案一次只能用于一次测量。

Now I have data 包含关闭:

大约 30 只狗; 每个都有 24 个测量值(分为几个子组); 每次测量至少有 4 个触点(每个爪子一个)和 每个联系人分为5个部分和 具有多个参数,如接触时间、位置、总力等。

显然,将所有东西都粘在一个大对象中并不能解决问题,所以我认为我需要使用类而不是当前的大量函数。但是即使我已经阅读了 Learning Python 的关于类的章节,我也无法将它应用到我自己的代码中 (GitHub link)

我也觉得每次我想得到一些信息时处理所有数据是相当奇怪的。一旦我知道了每只爪子的位置,我就没有理由再计算它了。此外,我想比较同一只狗的所有爪子,以确定哪个接触属于哪个爪子(前/后,左/右)。如果我继续只使用函数,这将变得一团糟。

所以现在我正在寻找有关如何创建类的建议,这些类可以让我以合理的方式处理我的数据 (link to the zipped data of one dog)。

【问题讨论】:

您可能还想考虑使用数据库(如 sqlite:docs.python.org/library/sqlite3.html)。您可以编写一个程序来读取大量数据文件并将其转换为数据库表中的行。然后作为第二阶段,您可以编写程序从数据库中提取数据以进行进一步分析。 You mean something like I asked here@ubutbu?我正计划这样做,但首先我希望能够以更有条理的方式处理所有数据 【参考方案1】:

如何设计一个类。

    写下单词。你开始这样做了。有些人不知道他们为什么会遇到问题。

    将您的单词集扩展为关于这些对象将要做什么的简单陈述。也就是说,写下你将对这些事情进行的各种计算。您的 30 条狗、24 次测量、4 次联系人和每个联系人的几个“参数”的简短列表很有趣,但这只是故事的一部分。您的“每只爪子的位置”和“比较同一只狗的所有爪子以确定哪个接触属于哪个爪子”是对象设计的下一步。

    在名词下划线。严重地。有些人争论这个的价值,但我发现这对于初次接触 OO 的开发人员来说是有帮助的。在名词下划线。

    复习名词。像“参数”和“测量”这样的通用名词需要用特定的、具体的名词替换,这些名词适用于您的问题域中的问题。细节有助于澄清问题。泛型只是省略了细节。

    对于每个名词(“contact”、“paw”、“dog”等),写下该名词的属性以及该对象参与的动作。不要走捷径。每个属性。例如“数据集包含 30 条狗”很重要。

    对于每个属性,确定这是否与定义的名词或其他类型的“原始”或“原子”数据(如字符串或浮点数或不可约化的数据)相关。

    李>

    对于每个动作或操作,您必须确定哪个名词负责,哪些名词仅参与。这是一个“可变性”的问题。有些对象会更新,有些则不会。可变对象必须对其突变承担全部责任。

    此时,您可以开始将名词转换为类定义。一些集合名词是列表、字典、元组、集合或命名元组,您不需要做很多工作。其他类更复杂,要么是因为复杂的派生数据,要么是因为执行了一些更新/变异。

不要忘记使用 unittest 单独测试每个类。

此外,没有规定类必须是可变的。例如,在您的情况下,您几乎没有可变数据。您拥有的是派生数据,由源数据集中的转换函数创建。

【讨论】:

【参考方案2】:

以下建议(类似于@S.Lott 的建议)来自本书Beginning Python: From Novice to Professional

    写下您的问题的描述(问题应该如何处理?)。在所有名词、动词和形容词下划线。

    遍历名词,寻找潜在的类。

    浏览动词,寻找可能的方法。

    浏览形容词,寻找潜在属性

    为您的类分配方法和属性

为了完善课程,本书还建议我们可以执行以下操作:

    写下(或构想)一组用例——关于如何使用您的程序的场景。尽量涵盖所有功能。

    逐步考虑每个用例,确保涵盖我们需要的所有内容。

【讨论】:

最好有一些我们应该写的句子的例子。【参考方案3】:

我喜欢 TDD 方法... 因此,首先为您希望的行为编写测试。并编写通过的代码。在这一点上,不要太担心设计,只需获得通过的测试套件和软件即可。如果您最终得到一个又大又丑的类,而且方法复杂,请不要担心。

有时,在这个初始过程中,您会发现一个难以测试的行为,需要对其进行分解,只是为了可测试性。这可能暗示需要一个单独的类。

然后是有趣的部分……重构。拥有工作软件后,您可以看到复杂的部分。通常情况下,一些小行为会变得明显,暗示一个新类,但如果没有,只需寻找简化代码的方法。提取服务对象和值对象。简化您的方法。

如果您正确使用 git(您正在使用 git,不是吗?),您可以在重构期间非常快速地尝试一些特定的分解,然后放弃它并在它不能简化事情时恢复。

通过首先编写经过测试的工作代码,您应该可以深入了解使用设计优先方法无法轻松获得的问题域。编写测试和代码会让你摆脱“我从哪里开始”的瘫痪。

【讨论】:

我也同意这个答案,尽管如果问题要由以下人员并行处理,那么分解问题并识别可能的类(即做“刚刚好”的软件架构)可能非常有用几个团队成员。【参考方案4】:

OO 设计的整个理念是让您的代码映射到您的问题,因此,例如,当您想要一只狗的第一步时,您可以执行以下操作:

dog.footstep(0)

现在,对于您的情况,您可能需要读取原始数据文件并计算足迹位置。所有这些都可以隐藏在 footstep() 函数中,这样它只会发生一次。比如:

 class Dog:
   def __init__(self):
     self._footsteps=None 
   def footstep(self,n):
     if not self._footsteps:
        self.readInFootsteps(...)
     return self._footsteps[n]

[现在这是一种缓存模式。它第一次去读取足迹数据,随后它只是从 self._footsteps 中获取它。]

但是,正确的 OO 设计可能很棘手。更多地考虑您想要对数据执行的操作,这将告知您需要将哪些方法应用于哪些类。

【讨论】:

【参考方案5】:

写出你的名词、动词、形容词是一种很好的方法,但我更喜欢将类设计视为问问题应该隐藏哪些数据

假设你有一个Query 对象和一个Database 对象:

Query 对象将帮助您创建和存储查询——存储是这里的关键,因为函数可以帮助您轻松地创建查询。也许你可以留下:Query().select('Country').from_table('User').where('Country == "Brazil"')。语法并不重要——那是你的工作! -- 关键是对象正在帮助您隐藏一些东西,在这种情况下是存储和输出查询所需的数据。对象的力量来自使用它的语法(在这种情况下是一些巧妙的链接),并且不需要知道它存储了什么来使其工作。如果操作正确,Query 对象可以输出对多个数据库的查询。它在内部存储特定格式,但在输出时可以轻松转换为其他格式(Postgres、mysql、MongoDB)。

现在让我们考虑一下Database 对象。这隐藏和存储了什么?很明显它不能存储数据库的全部内容,因为这就是我们有数据库的原因!那么有什么意义呢?目标是向使用Database 对象的人隐藏数据库的工作方式。好的类在处理内部状态时会简化推理。对于这个Database 对象,您可以隐藏网络调用的工作方式、批量查询或更新,或者提供缓存层。

问题是这个Database 对象是巨大的。它代表了如何访问数据库,因此在幕后它可以做任何事情。显然,根据您的系统,网络、缓存和批处理很难处理,因此将它们隐藏起来会非常有帮助。但是,正如许多人会注意到的那样,数据库非常复杂,并且您获得的原始数据库调用越远,就越难以调整性能并了解事物的工作原理。

这是 OOP 的基本权衡。如果您选择正确的抽象,它会使编码更简单(字符串、数组、字典),如果您选择太大的抽象(数据库、电子邮件管理器、网络管理器),它可能会变得太复杂而无法真正理解它是如何工作的,或者是什么预计。目标是隐藏复杂性,但一些复杂性是必要的。一个好的经验法则是一开始就避免使用Manager 对象,而是创建类似于structs 的类——它们所做的只是保存数据,并使用一些辅助方法来创建/操作数据以使您的生活更轻松。例如,在EmailManager 的情况下,从一个名为sendEmail 的函数开始,该函数接受一个Email 对象。这是一个简单的起点,代码很容易理解。

对于您的示例,请考虑需要将哪些数据放在一起来计算您要查找的内容。例如,如果您想知道动物走了多远,您可以有 AnimalStepAnimalTrip(AnimalSteps 的集合)类。现在每个 Trip 都有所有的 Step 数据,那么它应该能够弄清楚它,也许AnimalTrip.calculateDistance() 是有道理的。

【讨论】:

【参考方案6】:

浏览您的链接代码后,在我看来,您最好在这一点上设计一个 Dog 类。相反,您应该使用Pandas 和dataframes。数据框是带有列的表。您的数据框将包含以下列:dog_idcontact_partcontact_timecontact_location 等。 Pandas 在后台使用 Numpy 数组,它为您提供了许多方便的方法:

选择狗,例如:my_measurements['dog_id']=='Charly' 保存数据:my_measurements.save('filename.pickle') 考虑使用pandas.read_csv() 而不是手动读取文本文件。

【讨论】:

以上是关于如何在 Python 中设计一个类?的主要内容,如果未能解决你的问题,请参考以下文章

如何在故事板中设计 UIScrollView

如何在 reduxjs 中设计独立模块?

我如何在猫鼬中设计一个 json 结果?

如何在java中设计JPA多态关系?

如何在 node.js 中设计持久化服务

如何复制故事板中设计的 UIView?