《数据结构与算法 python语言描述》学习笔记(二)————抽象数据类型和Python类

第一部分:学习内容概要

  • 抽象数据类型
  • Python的类

第二部分:学习笔记

  • 抽象数据类型
      1.抽象数据类型(Abstract Data Type,ADT),通过一套接口阐述说明这一程序部分的可用功能,但不不限制功能的实现方法。
      
      2.抽象数据类型(ADT)的基本想法是把数据定义为抽象地集合,只为他们定义可用的合法操作,并不暴露其内部实现的具体细节,不论是其数据的表示细节还是操作的实现细节。
  • Python的类
      1.用class定义抽象数据类型(ADT)
      
      2.有下划线_开头的属性名(和函数名)都当作内部使用的名字,不应该在这个类之外使用。
      
      3.Python类的静态方法(@staticmethod),静态方法的参数表中不应该有self参数,在其他方面没有任何限制。静态方法就是在类里面定义的普通函数,但也是该类的局部函数。
      (举个栗子)
class Fuc(object):

    @staticmethod
    def get_num(m, n):
        if m > n:
            return m
        else:
            return n

    def __init__(self, m, n):
        self.a = self.get_num(m, n)
        self.b = self.a*2


result = Fuc(5, 6)
print(result.a, result.b)

 输出结果为 6 12
  上面这个程序是定义一个比大小的类,里面的get_num函数是一个静态方法,不需要将第一个参数设置为self,在内部与外部都可以直接调用。

  4.Python的类方法(@classmethod),这种方法必须有一个表示其调用类的参数,习惯用cls作为参数名,还可以有任何多个其他参数。类方法也是类对象的属性,通常用类方法实现与本类的所有对象有关的操作。
  (举个栗子)

class Fuc(object):

    count = 0

    @classmethod
    def count_num(cls):
        return Fuc.count

    @staticmethod
    def get_num(m, n):
        if m > n:
            return m
        else:
            return n

    def __init__(self, m, n):
        self.a = self.get_num(m, n)
        self.b = self.a*2
        Fuc.count += 1


result1 = Fuc(5, 6)
result2 = Fuc(7, 8)
result3 = Fuc(9, 10)
print(Fuc.count_num())

 输出结果为 3
  还是原来的程序,在class里多定义了一个类方法,来记录该类被调用的次数,count_num函数对属性count进行操作。
  
  5.类的继承之super()函数,如果在一个方法函数的定义里出现super().m(…)这种调用语句,执行到这个语句时,Python解释器就会从这个对象所属类的积累开始,用属性检索规则查找函数m。
  (举个栗子)

class A(object):

    def __init__(self):
        print("A被调用了")

    def a(self):
        print("a被使用了")


class B(A):

    def b(self):
        print("b被使用了")

    def __init__(self):
        super().a()
        print("B被调用了")


class C(B):

    def c(self):
        print("c被使用了")

    def __init__(self):
        super().a()
        super().b()
        self.c()
        print("C被调用了")


a = A()
b = B()
c = C()

 输出结果为
  A被调用了
  a被使用了
  B被调用了
  a被使用了
  b被使用了
  c被使用了
  C被调用了

第三部分:练习

  • 一般练习
    1. 复习概念
    2. 请例举出数据类型的三类操作,说明他们的意义和作用
      答:
        int、float、str意义和作用具体略了(根据算法内容要求改变数据类型)
    3. 为什么需要初始化函数,其重要意义和作用是什么?
      答:
        一个类能有无数个实例化对象,为了能对新的实例化对象初始化。
    4. 设法说明在实际中某些类型应该定义为不变类型,另一些类型应该定义为可变类型。请各举出两个栗子。
      答:
        python中的str、tuple、frozenset是不变类型;list、set、dict是可变类型
    5. 请简要说明在定义一个数据类型时应该考虑哪些问题?
      答:
        要考虑该数据类型在程序中的合适性,看能不能满足该程序的需求;也要考虑会不会对使程序导致不易阅读和理解,使程序难以编写正确,难以修改的问题。
    6. 请检查本章给出的Date抽象数据类型,讨论其中操作的语意说明里有哪些不精确之处,设法做些修改,消除描述中的歧义性。
      答:
        ③plus(Date d, int n)     #计算出过了n天之后的日期d
        ⑤adjust(Date d, int n)     #将日期d调整(向前调成或向后调成)n天的日期
    7. 请解释并比较类定义中的三类方法:实例方法、静态方法和类方法。
      答:
        实例方法:用self作为函数的第一个参数,类的实例化对象调用方法时需要用到。
        静态方法和类方法上面学习笔记里解释了,略。
    8. 列出Python编程中有关类属性命名的约定。
      答:
        ①:由下划线_开头的属性名都当作内部使用的名字,不应该在这个类之外使用。
        ②:以两个下划线开头(但不以两个下划线结尾)的名字做特殊处理,使类定义之外不能直接用这个名字访问。
    9. 请通过实例比较类作用域与函数作用域的差异。
      答:
        函数作用域:局部名称的作用域可以自动延伸到内部嵌套的函数中。
        类作用域:类C中定义的名字,不会自动延伸到C内部嵌套的作用域中。
    10. 是比较本章采用元祖实现有理数和采用类实现有理数的技术,讨论这两种方法不同方式各自的优点和缺点。
      答:
        元祖形式:①优点:可以有效解决管理上的问题,简洁。
             ②缺点:会产生歧义,比如与坐标(3, 4)可能会搞混;对于元祖里面的数据类型没有明确固定;运算带来不便。
        类定义: ①优点:解决了所有问题。
             ②缺点:烦琐,要指明的东西多,需要思路清晰。
  • 编程练习
    1. 定义一个表示时间的类Time,它提供下面操作:
      a)Time(hours、minutes、seconds)创造一个时间对象;
      b)t.hours()、t.minutes()、t.seconds()分别返回时间对象t的小时、分钟和秒值;
      c)为Time对象定义加法和减法操作(用运算符“+”、“-”);
      d)定义 时间对象的等于和小于关系运算(用运算符“==”、“<”);
      注意:Time类的对象可以采用不同的内部表示方式。例如:可以给每个对象定义三个数据属性hours、minutes、seconds,基于这种表示实现操作。也可以用一个属性seconds,构造对象时算出参数相对于基准时间0点0分0秒的秒值,同样可以实现所有操作。请从各方面权衡利弊,选择合适的设计。

  

class Time(object):

    def __init__(self, hours, minutes, seconds):
        if hours < 24:
            self.hour = hours

        if minutes < 60:
            self.minute = minutes

        if seconds < 60:
            self.second = seconds

    def hours(self):
        try:
            return self.hour
        except AttributeError:
                return "输入hours有误,请小于24时"

    def minutes(self):
        try:
            return self.minute
        except AttributeError:
                return "输入minutes有误,请小于60分"

    def seconds(self):
        try:
            return self.second
        except AttributeError:
                return "输入seconds有误,请小于60秒"

    def __add__(self, other):
        new_second = self.second + other.second
        new_minute = self.minute + other.minute
        new_hour = self.hour + other.hour
        if new_second >= 60:
            new_minute += 1
            new_second = 0
        if new_minute >= 60:
            new_hour += 1
            new_minute = 0
        if new_hour >= 24:
            new_hour = 0

        return new_hour, new_minute, new_second

    def __sub__(self, other):
        new_second = self.second - other.second
        new_minute = self.minute - other.minute
        new_hour = self.hour - other.hour
        if new_second < 0:
            new_minute -= 1
            new_second = new_second + 60
        if new_minute < 0:
            new_hour -= 1
            new_minute = new_minute + 60
        if new_hour < 0:
            new_hour = new_hour + 24

        return new_hour, new_minute, new_second

    def __eq__(self, other):
        if (self.second == other.second) and (self.minute == other.minute) and (self.hour == other.hour):
            return True
        return False

    def __lt__(self, other):
        if self.hour < other.hour:
            return True
        elif (self.hour == other.hour) and (self.minute < other.minute):
            return True
        elif (self.hour == other.hour) and (self.minute == other.minute) and (self.second < other.second):
            return True
        else:
            return False


t1 = Time(21, 59, 52)
t2 = Time(11, 30, 30)
print(t1.hours(), t1.minutes(), t1.seconds(), sep="\n")
print(t1 - t2)
print(t2 - t1)
print(t1 < t2)
print(t2 < t1)
print(t1 == t2)

  
2. 请定义一个类,实现本章描述的Date抽象数据类型。
  

"""

这里Date里简略的将每个月都视为30天,一年为360天

"""


class Date(object):

    def __init__(self, year=2018, month=10, day=5):
        self.year = year
        self.month = month
        self.day = day

        if self.year < 0:
            self.year = 0
            print("输入年份出错,年份请大于0年")
        if self.month < 1:
            self.month = 1
        elif self.month > 12:
            self.month = 12
            print("输入月份出错,月份请大于或等于1月,小于或等于12月")
        if self.day < 1:
            self.day = 1
        elif self.day > 30:
            self.day = 30
            print("输入日期出错,日期请大于或等于1号,小于或等于30号")

    def __str__(self):
        return "{}年{}月{}日".format(self.year, self.month, self.day)

    def difference(self, other):

        d1 = self.year * 360 + self.month * 30 + self.day
        d2 = other.year * 360 + other.month * 30 + other.day
        result = d1 - d2
        if result < 0:
            result = -1 * result
        return "两个日期差%d天" % result

    def plus(self, n):
        day, month, year= self.day, self.month, self.year
        day = day + n
        while day > 30:
            month = month + 1
            day -= 30

        while month > 12:
            year = year + 1
            month -= 12

        return "{}年{}月{}日".format(year, month, day)

    def num_date(self, year, n):
        year = self.year
        month = 1
        if n > 360 or n < 0 :
            print("找不到这天,输入的天数有误")
        else:
            while n > 30:
                month += 1
                n -= 30
            if month > 12:
                return "范围出错,找不到这天"
        day = n
        return "{}的{}天是{}月{}日".format(year, n,  month, day)

    def adjust(self, n):
        self.day += n
        if self.day > 0:
            while self.day > 30:
                self.day -= 30
                self.month += 1
            while self.month > 12:
                self.month -= 12
                self.year += 1
        else:
            while self.day < 0:
                self.day += 30
                self.month -= 1
            while self.month < 1:
                self.year -= 1
                self.month += 12
            if self.year < 0:
                return "调整日期出错,超出范围"

        return "{}年{}月{}日".format(self.year, self.month, self.day)

  
  3. 请扩充本章给出的有理数类,加入一些功能:
  a)其他运算符的定义;
  b)各种比较和判断运算符的定义;
  c)转换到整数(取整)和浮点数的方法;
  d)给初始化函数加入从浮点数构造有理数的功能;

def __sub__(self, another):
    den = self._den * another.den()
    num = (self._num * self.den() - self._den * another.num())
    return Rational(num, den)
    
def __ne__(self, another):
    return self._num * another.den() != self._den * another.num()

def change(self):
    return self._den//self._num         #转换到int
    return self._den/self._num          #转换到float

def change_r(self):
    return float.as_integer_ratio(self._den / self._num)

  
  4. 本章2.2.2节中有理数类的实现有一个缺点:每次调__init__都会对两个参数做一遍彻底检查。但是,在有理数运算函数中构造结果时,其中一些检查并不必要,浪费了时间。请查阅Python手册中与类相关的机制,特别是名字为__new__的特殊方法等,修改有关设计,是得到的实现能完成工作但又能避免不必要的检查。
  

class Rational(object):

    def __new__(cls, num, den=1):
        if not isinstance(num, int) or not isinstance(den, int):
            raise TypeError
        return object.__new__(cls)

    def __init__(self, num, den=1):
        if den == 0:
            raise ZeroDivisionError
        "........"

  
  5. 请基于2.5节的工作继续扩充,为该学校人事系统定义研究生类、教师类和职员类。
  
  略略略  

第四部分:总结

  以上记录的是自己学习的过程,课后练习也全是凭借个人理解来完成的,正确答案以及方式有待商榷,如果有大神偶然看见小弟的这篇笔记,有不对的地方也恳请斧正,谢谢。

你可能感兴趣的:(学习笔记)