Python OO程序结构规划

时间:2017-01-15 12:09:04

标签: python oop data-structures project-planning

我是OOP的初学者,我想创建一个包含三个类A,B和C的程序。该类的每个实例都由一组特征Achar1,Achar2等定义。

程序应该创建使用,包括A的元素,B的元素和C的元素以及开始和结束日期。有A和B的子类,因此A的某些元素只能连接到B的某些元素。程序的主要功能是列出A,B和C的元素及其属性,列表使用< / em>并建议新的使用,这将最大限度地减少使用类的实例,以避免重复。

我的第一直觉是使用三个字典A,B和C以及字典供使用。这似乎直观,易于导入/导出到json或类似。我试图重写它来使用类,但是我看不出这样做有什么好处:很难(?)迭代类的实例,而且它们基本上都是字典,因为这些数据不需要太多其他东西。

我做错了什么?从字典切换到对象可以获得什么?

编辑:有问题的代码(基于字典)是here。我尝试使其面向对象的第一个版本是here

3 个答案:

答案 0 :(得分:9)

从字典切换到对象可以获得什么?

这是一个非常广泛的问题。

在Python中,对象在语义上等同于字典,因为对象几乎等同于其__dict__属性(我不会详细说明这个&#34)几乎&#34;在这里,因为它远离主题)。

我认为使用类而不是字典有两个主要好处:抽象和舒适。

抽象

当您处于设计阶段时,特别是对于中短程序,您通常希望在思考时编写代码的骨架。

在你需要模拟互动的情况下,在课堂上思考更自然,因为它在说话和编程之间。

这使您更容易理解自己的问题。此外,它极大地提高了代码的可读性,因为它看起来很自然,即使读者对代码一无所知也是如此。

这为您带来了继承和多态等概念,丰富了OOP提供的抽象。

舒适

Python的许多优势之一是data model。丰富的魔术方法和属性允许您使用非常简单的语法。此外,它可以在您的位置处理一些操作。

以下是命令式和面向对象编程之间的一些比较在Python中

当然,Python中的所有内容都是一个对象,所以即使在命令式示例中我也会使用点调用(foo.bar())。

正在阅读的文件

势在必行

f1 = open(in_path, 'r')
f2 = open(out_path, 'w')
for line in f1:
    processed = process(line)
    f2.write(processed)

# Oops, I forgot to close my files...

面向对象的方式

with open(in_path, 'r') as f1, open(out_path, 'w') as f2:    
    for line in f1:
        processed = process(line)
        f2.write(processed)

# I don't have to close my files, Python did it for me

请注意for line in f是Python面向对象数据模型的广泛使用。想象一下如果这种语法不存在就会产生痛苦(好吧,只需在C语言中尝试)。

空虚测试

势在必行

if len(some_list) == 0:
    print("empty list")

面向对象的方式

if some_list:
    print("empty list")

对序列进行迭代

势在必行

i = 0
while i < len(some_sequence):
    print(some_sequence[i])
    i += 1

面向对象的方式

for elt in some_sequence:
    print(elt)

但是这个数据模型的实际优势在于它可以让你重新定义很多魔法属性。例如,您可以通过实施__lt____le__等来制作具有可比性的复杂内容,这将重新定义<<=的行为,等等。从那时起,minmaxsort等内置函数将了解如何比较对象。

这就是说,在各种各样的情况下使用单纯的词典就足够了。

在一天结束时,OOP只是一种范式,而命令式编程也可以正常运行。

答案 1 :(得分:3)

tl; dr答案是多态性

类本身并不比dicts更好,只适用于不同的问题域。如果要创建3个行为类似于dicts的对象,则只需使用dicts。因此,如果A,B和C都是决定并且解决了你的问题,那么你就完成了:dicts是正确的选择。

如果它们实际上是不同的数据结构和可能完全不同的实现,那么dicts就不是正确的答案。

但是,在这种情况下,(这是类帮助您的地方),类提供多态来帮助您解决所述问题。这是多个对象虽然属于不同的类,但每个对象都可以以自己的方式响应相同的方法。

因此,您可以为类A,B和C实现“使用”方法。这些类的对象现在将响应该方法,即使其实现的其余部分完全不同。

这最容易在基本类的__str__函数中表示。

>>> x = 1
>>> x.__str__()
'1'
>>> x = "hello"
>>> x.__str__()
'hello'

没有人会将整数(即做数学)的函数与字符串的函数(即存储文本)混淆,但它们都会响应同一条消息__str__。这就是为什么以下工作原理:

>>> y = 1
>>> z = "hello"
>>> y.__str__() + z.__str__()
'1hello'

所以在你的情况下,你可以有三个类A,B和C,它们的实现完全不同,但是给它们提供一个类似的方法“use”。然后,当你问他们所有“使用”时,他们都会以同样的方式回答,你可以编译你的使用清单。

您的代码充满了长“case”语句,以下是关于如何使用多态来删除它们的一个很好的讨论:

Ways to eliminate switch in code

您应该能够通过消除所有控制语句(ifs)并将消息发送到对象来大幅减少您拥有的代码量,尤其是所有重复部分。让对象弄清楚要做什么。您的对象应该具有“import”,“export”和“add”等方法。

答案 2 :(得分:0)

如果你只是从dict扩展每个类并个性化他们的行为怎么办?

class classA(dict):
    '''Some personalization here...'''
    def __init__(self, **kwargs):
        pass

我的意思是......它们仍然是字典,可以作为词典,但你可以定义一些自己的方法。

修改

好的......我读了你的代码并尝试从中做一些O​​OP。不是最好的OOP,但你可以得到这个想法。代码更清晰,更易于调试,更易于扩展,更易于维护等等......

这是dropbox文件夹: https://www.dropbox.com/sh/8clyys2gcnodzkq/AACXhPnCW5d9fx0XY6Y-y_6ca?dl=0

您怎么看?