《数据结构与算法——Python语言描述》笔记(4)

第2章 抽象数据类型和python类

2.1 抽象数据类型

ADT(Abstract Data Type)是一种思想,也是一种组织程序的技术,主要包括:

1、围绕着一类数据定义程序模块。

2、模块的接口和实现分离。

3、在需要实现时,选择一套合适的机制,采用合理的技术,实现这种ADT的功能,包括具体的数据表示和操作。


2.2 Python中的类

本节主要讲python利用class实现抽象数据类型。

class Rational_number():
    def __init__(self,num,den=1):
        self.num=num
        self.den=den

    def plus(self,another):
        den=self.den*another.den
        num=self.den*another.num+self.num*another.den
        # 求最大公约数,保证可以被约到最简形式
        max=self.greatest_common_divisor(num,den)
        den=den/max
        num=num/max
        # int()确保输出的是整数
        return Rational_number(int(num),int(den))

    # 求两个数的最大公约数
    def greatest_common_divisor(self,a,b):
        if a

下面对这段代码做说明:

  • class是类的关键字,后面跟类名和冒号,此行称为类定义的头部,后面就是类定义的体部分了。上面定义了一个有理数的类。
  • 类体部分是一批函数,称为类的方法,最重要的方法是操作本类的实例对象的方法,称为实例方法,这种方法总是从本类的对象出发去调用,其参数列表里面的第一个参数就是实际调用时的调用对象,通常以self为参数的名字。
  • 在一个类里面,__int__方法称为初始化方法,用于构造本类的新对象,比如用a=Rational_number(3,2)创建一个对象,并赋给变量a,调用式应给出除self之外的其他实际参数。
  • self.num形式的写法表示本类实例对象的属性,num是属性名。在初始化方法中,创建本类对象的时候就会为它的属性赋值。
  • 类的其他实例方法也应该以self为第一个参数,调用时以实例对象名.方法名(参数)。如果只有一个self参数,则为实例对象名.方法名()。

        类定义的作用是支持创建抽象的数据类型,在建立这种抽象时人们不希望暴露其实现的内部细节。如对于有理数类,不希望暴露这种对象内部是用两个整数表示分子和分母。需要为此而隐藏一些信息。

        在python中,以单下划线开头的属性名和函数名是内部使用的名字,在类外不能使用,另外,python对类定义里面以两个下划线开头(不能是结尾)的名字做了特殊处理,不能在类定义之外访问。(类的私有成员函数或者变量)

        考虑上面代码中求最大公约数的方法,该函数并不依赖与有理数的对象,因此第一个参数无需使用self,即它不需要作为类的实例方法出现,我们将其定义为类的非实例方法(静态方法)描述时需要在函数定义的头部行之前加上修饰符@staticmethod。静态方法就是类里面的普通函数,也是该类的局部函数,调用时用类名.方法名(参数)

        还有一个问题需要考虑,在有理数类的初始化方法中没有检查参数,首先要检查是否参数均为正数,然后分母是否为0,如果不满足,则抛出异常。而且分子分母可能为正或负,需要将符号加到公约化简后的分子上去。(实验发现,如果去掉了@staticmethod没有什么影响。)

class Rational_number():
    def __init__(self,num,den=1):
        if not isinstance(num,int) or not isinstance(den,int):
            raise TypeError
        if den==0:
            raise ZeroDivisionError
        sign=1
        if num<0:
            num,sign=-num,-sign
        if den<0:
            den,sign=-den,-sign
        g=Rational_number._greatest_common_divisor(num,den)
        # 在python3.0中,"/"表示浮点数除法,返回浮点结果;"//"表示整数除法,返回整数结果。
        self._num=sign*(num//g)
        self._den=den//g

    # 求两个数的最大公约数
    @staticmethod
    def _greatest_common_divisor(a,b):
        if b==0:
            a,b=b,a
        while a!=0:
            a,b=b%a,a
        return b

        下面考虑类内其他的方法。由于两个属性_den和_num均被设置为内部属性,不应该在类外引用他们,但在实际计算中,我们有时需要提取分子和分母,为此需要有一对解析的操作(也是实例方法):

   def get_num(self):
        return self._num

    def get_den(self):
        return self._den

       考虑有理数的运算,人们希望用(+,-,*,/)等运算符来描述计算过程,写出更加自然的表达式,在python中,为所有的算术运算符规定了特殊的方法名。+运算符对应了__add__,*运算符对应了__mul__,%运算符对应了__mod__,/运算符对应了__truediv__,-运算符对应了__sub__。

    def __add__(self,another):
        den=self._den*another._den
        num=self._den*another._num+self._num*another._den
        # 求最大公约数,保证可以被约到最简形式
        max=Rational_number._greatest_common_divisor(num,den)
        den=den//max
        num=num//max
        return Rational_number(num,den)

在调用时,只需要用a+b即可。

        有理数经常要比较大小和不等,这些类进行比较时,也提供了特殊的方法名,如下面的定义:

    # 定义相等
    def __eq__(self, other):
        return self._den*other._num==self._num*other._den

    # 定义大于
    def __gt__(self, other):
        return self._den * other._num < self._num * other._den

    # 定义小于
    def __lt__(self, other):
        return self._den * other._num > self._num * other._den

        为了便于输出,人们经常在类定义里面定义一个将该类对象转换到字符串的方法,为了保证系统的str函数可以正常使用,这个方法要采用特殊的名字__str__。内置函数str将调用它。

下面是完整的程序,此时的有理数类以及和python系统内部的类型没有什么差别了,地位和用法相同,python标准库的一些类型就是如此定义的。

class Rational_number():
    def __init__(self,num,den=1):
        if not isinstance(num,int) or not isinstance(den,int):
            raise TypeError
        if den==0:
            raise ZeroDivisionError
        sign=1
        if num<0:
            num,sign=-num,-sign
        if den<0:
            den,sign=-den,-sign
        g=Rational_number._greatest_common_divisor(num,den)
        # 在python3.0中,"/"表示浮点数除法,返回浮点结果;"//"表示整数除法,返回整数结果。
        self._num=sign*(num//g)
        self._den=den//g

    def __add__(self,another):
        den=self._den*another._den
        num=self._den*another._num+self._num*another._den
        # 求最大公约数,保证可以被约到最简形式
        max=Rational_number._greatest_common_divisor(num,den)
        den=den//max
        num=num//max
        return Rational_number(num,den)

    # 定义相等
    def __eq__(self, other):
        return self._den*other._num==self._num*other._den

    # 定义大于
    def __gt__(self, other):
        return self._den * other._num < self._num * other._den

    # 定义小于
    def __lt__(self, other):
        return self._den * other._num > self._num * other._den

    # 求两个数的最大公约数
    @staticmethod
    def _greatest_common_divisor(a,b):
        if b==0:
            a,b=b,a
        while a!=0:
            a,b=b%a,a
        return b

    def get_num(self):
        return self._num

    def get_den(self):
        return self._den

    def __str__(self):
        return str(self._num)+"/"+str(self._den)

    def print_number(self):
        # str(实数)可以将实数转化为字符串
        print(self._num,"/",self._den)

a=Rational_number(3,4)
b=Rational_number(5,2)
(a+b).print_number()
print((a+b).__str__())
t=type(a)
print(t)
print(a>b)

你可能感兴趣的:(Python)