《数据结构与算法Python语言描述》裘宗燕 笔记 第二章 抽象类型

 

《数据结构与算法Python语言描述》裘宗燕 笔记系列
该系列笔记结合PPT的内容整理的,方便以后复习,有需要的朋友可以看一下。

源码重新整理了

 

地址:https://github.com/StarsAaron/DS/tree/master

 

 

抽象数据类型

抽象数据类型的思想:

采用某种数据形式表示所需的数据“类型”

并定义一组操作,实现对有关数据对象的所需操作

用元组实现有理数(如上学期的示例),可以看作抽象数据类型的一种实现。但这种实现不够理想,因为它不抽象

只是元组的具体应用,不是新类型,不具有类型的特点

Python 内置类型是“抽象数据类型”,符合上面的思想

许多 Python 标准库包实现某种数据类型,它们像内置类型一样是实实在在的抽象,如标准库手册第 8 节介绍的各种数据类型包

在写复杂程序时,如果能自己创建与内置类型性质和使用方式类似的

“用户定义类型”,有可能把程序组织得更好

这样定义类型是建立“数据抽象”(与 [计算] 过程抽象对应),定义的一个抽象

 

抽象数据类型和 Python 的 class

Python 提供了支持定义数据抽象的机制

定义数据类型的标准 Python 机制是 class 定义(类定义)定义一个类(class)就是定义一个新类型

定义好的类可以像内置类型一样使用,包括生成类的实例(类的实例称为对象,object,在前面讨论中反复提到)

在类定义里,可以为本类的实例定义一组相关操作

对一个类的实例对象,可以使用类里定义的这些操作

Python 的基本系统就是基于类和对象构造起来的

class 是 Python 语言 基本的概念,许多重要问题需要用 class 及其性质解释

例如:Python 内部类型的性质,异常和异常处理等

标准库包的抽象数据类型都是用 class 定义的

 

类与面向对象的编程

定义类,生成类的对象,基于这种对象组织和描述计算,这一套做法称为面向对象编程(Object Oriented Programming,OOP)

OOP 是软件领域 重要的技术,有利于分解系统的复杂性

许多复杂软件系统都是用 OOP 技术开发的

 

Python 也称为是一种面向对象的编程语言

类是在基本计算结构(表达式/语句/函数定义)之上的高级结构

语法:

class C :  # 定义一个以 C 为名字的类语句块

class C (B) : # 基于已有类 B 扩充定义一个新类 C 语句块裘宗燕,2014-9-24-/68/

类定义中的程序块里通常是一组函数定义

用类定义数据抽象时,这种函数定义描述了该类的对象的行为

可以定义函数去创建、操作、生成该类的对象

 

下面考虑定义一个有理数类

给这个类取名 rational

该类的对象是具体的有理数

需定义各种有理数运算(操作),以便在程序里方便地使用它们

rational 类的定义: class rational :

__init__(self, num, den) : # __init__ 函数创建类的对象 

self.num = num             # 第一个参数 self 表示被创建对象

self.den = den               # 通过 self 和圆点给对象的成分赋值

... ...                                    # 成分的名字根据需要选择

类定义实例:有理数类

名字为 __init__ 的函数称为它所在类的构造函数

创建这个类的对象时,自动调用这个函数

在创建类的对象时,不需要为 __init__ 的第一个参数 self 提供值,但需要为其他参数提供值

r = rational(2,3)  # 建立一个 rational 类对象,2 和 3 是其成分

 

定义一个操作输出有理数对象

设计输出,采用分子/分母的形式,函数取名 print

函数定义(放在类定义的程序块里) def print(self) : print(self.num, "/", self.den)

函数的使用

r.print()

 

为类的对象定义操作(称为方法)和使用的要点:

方法的定义写在类的程序块里

方法的第一个参数表示操作对象,通常用 self 作为参数名,方法体里用该参数加圆点的形式引用对象的成分(取值或赋值)

当变量的值是本类的对象时,用圆点加方法名的形式调用方法,并为方法(除第一个参数外)的其他参数提供实参

定义一个到 str 类型的转换函数:

def __str__(self) :

return str(self.num) + "/" + str(self.den)

人们在定义类时,经常为其定义一个到 str 的转换函数

主要用途是从对象生成字符串,以便输出或在其他地方使用

 

有理数加法,例如用 plus 作为方法名:

def plus(self, another) :

den = self.den * another.den

num = (self.num * another.den + self.den * another.num) return rational(num, den)

注意:这里调用 rational 构造新有理数对象,而不直接构造 tuple

下面会看到这种统一描述带来的收益

使用:

r1 = r.plus(rational(3, 4)) r2 = r1.plus(r)

我们可能觉得用这种形式写计算不自然, 好能用内置数类型的运算的写法,用 + - * / 等运算符

在 Python 里可以做这件事,需要用一些特殊的方法名裘宗燕,2014-9-24-/72/

表示运算符的特殊名见语言手册 3.3.7 节,包括: 

object.__add__(self, other) 

object.__sub__(self, other) 

object.__mul__(self, other) 

object.__truediv__(self, other) 

object.__floordiv__(self, other) 

object.__mod__(self, other)

object.__pow__(self, other[, modulo])

... ...

模拟算术运算的加法方法定义: 

def __add__(self, another) : 

den = self.den * another.den 

num = (self.num * another.den + self.den * another.num) 

return rational(num, den)

r3 = r2 + r1

 

使用这个 rational 类建立对象,做一些运算

>>> x = rational(3,5) >>> x = x + rational(7,10) x.print()

65 / 50

易见,定义的类没做分数化简,会导致分子分母变得很大

化简的数学基础很清楚,但怎么修改程序?

可以修改实现加法的方法,加入与化简有关的语句但还有减法、乘法、除法等。这样需要做许多重复工作

另一可能性是修改构造函数如果所有有理数都是用构造函数建立,一个修改就能解决所有问题

 

考虑所有可能情况(如分子/分母是负数,错误值等),有下面定义: 

def __init__(self, num, den = 1) :

if type(num) != int or type(den) != int : raise TypeError

if den == 0 :

raise ValueError

sign = 1 if (num < 0) : num, sign = -num, -sign if (den < 0) :

den, sign = -den, -sign

g = gcd(num, den) self.num = sign * (num//g) self.den = den//g

这里还需要一个求 大公约数的函数,可以是全局定义的,也可以定义在有理数类的里面

类定义实例:有理数类

增加其他运算已经没有任何困难了,请自己补充完整

剩下的问题一方面是数学,大家都熟悉

另一方面是具体运算的编程,可以参考 __add__ 的实现

把 rational 类的完整定义放入一个文件,作为一个模块

如果需要用有理数,import 这个模块,类型 rational 就有了定义

可以用 rational 建立有理数对象,用它提供的功能操作有理数

从使用的角度看,这个 rational 与内置的 int, list 等类型没有差别

对于 class 定义,还有一些功能和规定

有关情况可查看语言手册,其他参考书

上面讨论的是 规范的使用,基本满足本课程的需要,后面会根据情况考虑

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁星点点-

请我喝杯咖啡呗

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值