PYTHON1.面向对象_day02

课程:Python面向对象
进度:day2

上次内容回顾
1. 面向对象:以对象为中心
2. 三大特性:封装、继承、多态
3. 如何定义类、如何实现继承
     class 类名称(父类列表):
           # 构造函数
           # 其它成员函数

今天的内容
1. 多态:相同的方法,不同的表现(重点)
    1)事物除了共性外,还具有各自的特性(个性)
         多态就用来处理事物的个性
    2)多态能够在不影响父类行为(不修改父类代码)
         情况下,进行功能的扩展和变更
    3)使程序(软件设计)更具灵活性

2. 方法的重写:父类中定义过的方法子类中重新定义
    (重点)

3. 多态的实现:通过在子类中重写父类的方法实现多态(重点)
    (重点)
   
课堂练习:
编写一个手机类(Phone)
属性:名称(name), 价格(price),
           CPU, 屏幕尺寸( screen_size)
方法:开机(startup),关机(shutdown)
           打电话(call), 发短信(send_msg)
并编写测试代码
见 phone.py

PYTHON1.面向对象_day02
  1 # phone.py
  2 # 手机类
  3 import time
  4 class Phone:
  5     def __init__(self, name, price,
  6                  CPU, screen_size):
  7         self.name = name
  8         self.price = price
  9         self.CPU = CPU
 10         self.screen_size = screen_size
 11 
 12     def startup(self):
 13         print("正在开机")
 14         time.sleep(2)
 15         print("开机成功")
 16 
 17     def shutdown(self):
 18         print("正在关机")
 19         time.sleep(2)
 20         print("关机成功")
 21 
 22     def call(self, phone_no):
 23         print("正在拨号")
 24         time.sleep(1)
 25         print("正在和%s通话" % phone_no)
 26 
 27     def send_msg(self, phone_no, msg):
 28         print("正在向%s发送信息..." % phone_no)
 29         time.sleep(2)
 30         print("【%s】发送成功" % msg)
 31 
 32     def __del__(self):  # 析构方法
 33         print("__del__方法被调用")
 34 
 35 def fun():
 36     phone = Phone("华为",1999.99,
 37                  "双核2G", 5.5)
 38     print("fun()函数退出")
 39 
 40 if __name__ == "__main__":
 41     myphone = Phone("华为",1999.99,
 42                     "双核2G", 5.5)
 43     fun()
 44     print("程序退出")
 45     # myphone程序退出时被销毁
 46 
 47 
 48 
 49     myphone.startup()  #启动
 50     myphone.call("13512345678") #打电话
 51     myphone.send_msg("13512345678","你好")
 52     myphone.shutdown()  #关机
phone.py

PYTHON1.面向对象_day02

4. 面向对象的技术特性
   1)构造和析构
      a)构造方法(重点)
        - 名称:在Python中,固定为__init__
        - 作用:是为对象创建属性,并且赋予初始值
        - 调用时机:对象被创建(实例化)自动调用
        - 如果在类中未定义,Python会给出默认的构造方法
        - 在继承关系中,如果父类定义了__init__方法
          在子类的构造方法中,必须要调用父类的构造方法

       b)析构方法
          - 名称:__del__
          - 调用时机: 对象被销毁时自动调用
                               del obj, 局部变量退出作用于,程序退出
          - 作用:对象销毁时,执行清理操作

   2)多重继承:一个类有多个父类
       - 如何实现多继承: 定义类的时候,继承自多个父类,
             父类之间用逗号隔开
       - 语法格式:
             class 类名称(父类1, 父类2, ......):
                     语句块

       - 通过多重继承,子类具有所有父类的特征和行为
       - 如果多个父类具有相同的方法(或属性名称),通过
         类的__mro__属性中记录的顺序进行方法查找

        MRO(Method Resolution Order)

        总的原则按照由下至上、从左至右(继承列表中前后)
         进行查找,直到object类,如果都没有找到就报错

PYTHON1.面向对象_day02
  1 # mul_inh.py
  2 # 多重继承示例
  3 # 超人类继承自战士、飞行者、喷或者
  4 # 三个类
  5 class Fighter:  #战士类,默认继承自object
  6     def fight(self):
  7         print("我能战斗")
  8 
  9     def roar(self):  #吼叫
 10         print("战士吼叫:嗷嗷嗷")
 11 
 12 class Flyer:  #飞行者类
 13     def fly(self):
 14         print("我能飞行")
 15 
 16     def roar(self):  #吼叫
 17         print("飞行者吼叫:呜呜呜")
 18 
 19 class Firer: # 喷火者
 20     def fire(self):
 21         print("我能喷火")
 22 
 23 # 超人类,继承自Fighter,Flyer,Firer父类
 24 class SuperMan(Flyer,Fighter,Firer):
 25     pass
 26 
 27 if __name__ == "__main__":
 28     super_man = SuperMan() # 实例化超人对象
 29     super_man.fight()  # 超人战斗
 30     super_man.fly()    # 超人飞行
 31     super_man.fire()   # 超人喷火
 32     super_man.roar()   # 超人吼叫??
 33     # Mehtod Resolution Order
 34     # 决定调用哪一个类的方法
 35     # print(SuperMan.__mro__)
 36     print(SuperMan.__bases__) # __bases__绑定父类
 37     print(Fighter.__base__)
 38     print(Flyer.__base__)
 39 
mul_inh.py

PYTHON1.面向对象_day02  

3)object类:所有类的总父类,如果定义类时候,没有
       指定父类,则默认从object类继承

                         
       类的父类可以通过__base__属性查看

   4)super()和issubclass()
      - super()函数
        作用:返回绑定的父类
              有时候需要显式调用父类方法
              就使用super()函数
        格式:super(type, ojb) 返回obj对象父类
              super() 返回当前对象父类

                      只能在类的方法中调用

     - issubclass: 判断一个类是否是另一个
                    类的子类,如果是返回True
                    如果不是返回False
        格式:issubclass(cls, class_or_tuple)
        
5. 函数重写(重点,理解原理)
   1)对象转字符函数的重写
     - str:将对象转换成人阅读的字符串
            重写__str__()

     - repr: 返回字符串,给Python解释器阅读
             通过eval(repr(obj))能够还原obj
             对象,重写__repr__()

     - 当调用str(obj)将对象转换成字符串
       时,其搜索顺序为:
       + 优先查找obj.__str__()方法(包括父类)
       + 如果上一步不存在,则调用obj.__repr__()
       + 如果上一步不存在,则调用object.__repr__()

PYTHON1.面向对象_day02
  1 
  2 class A:
  3     def __init__(self, name):
  4         self.name = name
  5 
  6     def __str__(self):  # 重写__str__函数
  7         return "name = %s" % self.name
  8 
  9 class B(A):
 10     def __init__(self, name, id):
 11         super().__init__(name) # 调用父类构造方法
 12         self.id = id  # id属性被创建
 13 
 14     def __repr__(self):  # 重写__repr__方法
 15         # 返回例如"B('Jerry','0001')"
 16         return "B('%s','%s')" % (self.name, self.id)
 17 
 18     def __str__(self):  # 重写__str__函数
 19         return "name=%s,id=%s"%(self.name,self.id)
 20 
 21 b = B("Jerry", "0001")  # ==》
 22 print(b)
 23 
 24 # str_obj = repr(b)
 25 # print(str_obj)
 26 # new_obj = eval(str_obj)  # 通过调用eval函数还原对象
 27 # print(new_obj)
 28 
 29 # print(b)  # B类中重写__str__方法,所以可以直接打印
 30 # str_obj = str(b)  # 将b对象转换成字符串
 31 # print(str_obj)
 32 
 33 #super(B, b).print() # 根据对象b找到父类,并调用父类的print
 34 # print(issubclass(B, (A,object)))    # True
 35 # print(issubclass(B,object)) # True
 36 # print(issubclass(A, B))  # False
a.py

  2)内建函数重写
     - abs()函数:重写__abs__()
     - len()函数: 重写__len__()
     - reversed()函数: 重写__reversed__()
     - round()函数:重写__round__()
    
     课堂练习:重写__len__()和__round__()
               重写__reversed__()
     示例见my_list.py

PYTHON1.面向对象_day02
  1 # mylist.py
  2 # 自定义列表
  3 class MyList:
  4     def __init__(self, iterable=[]):
  5         self.data = [x for x in iterable]
  6 
  7     # 重写__abs__()函数
  8     def __abs__(self):
  9         #对每个元素求绝对值,用产生的结果实例化一个MyList对象
 10         return MyList(abs(x) for x in self.data)
 11 
 12     def __str__(self):  # 重写__str__()函数
 13         ret = ""
 14         for x in self.data:
 15             ret += str(x)  # 将元素由数字转换成字符串
 16             ret += " "
 17         return ret   # 返回结果串
 18 
 19     def __len__(self):  # 重写__len__函数,返回元素个数
 20         return len(self.data)
 21 
 22     # 对每个元素求近似值,并实例化对象返回
 23     def __round__(self):
 24         return MyList(round(x,2) for x in self.data)
 25 
 26     # 重写__reversed__,倒序
 27     def __reversed__(self):
 28         tmp = []
 29         x = len(self.data) - 1  # 最后元素下标
 30         while x >= 0:
 31             tmp.append(self.data[x])
 32             x -= 1   # 计数器减1
 33         return MyList(tmp)  # tmp是经过倒序的可迭代对象
 34 
 35     def __add__(self, other): # L1 + L2
 36         return MyList(self.data + other.data)
 37 
 38     def __mul__(self, value): # L1 * 2
 39         return MyList(self.data * value)
 40 
 41     def __eq__(self, other): # 重载==运算符
 42         len1 = len(self.data)  # 取data属性长度
 43         len2 = len(other.data) # 取另一个对象data的长度
 44         if len1 != len2: # 长度不相等,无需比较
 45             return False
 46 
 47         for i in range(0, len1):
 48             if self.data[i] != other.data[i]:
 49                 return False #只要出现元素不相等,返回False
 50         return True
 51 
 52     def __ne__(self, other): # 重载!=运算符
 53         return not (self == other)
 54 
 55     def __gt__(self, other):
 56         len1 = len(self.data)  # 取data属性长度
 57         len2 = len(other.data) # 取另一个对象data的长度
 58         min_len = min(len1, len2) # 获得循环上限
 59 
 60         for i in range(min_len): # 以长度短的作为循环上限
 61             if self.data[i] == other.data[i]:
 62                 continue
 63             elif self.data[i] > other.data[i]:
 64                 return True
 65             elif self.data[i] < other.data[i]:
 66                 return False
 67         if len1 == len2:  #相等
 68             return False
 69         elif len1 > len2: #前面的元素相等,长度比对方大
 70             return True
 71         else:
 72             return False
 73 
 74     def __neg__(self): #重载符号运算符
 75         return MyList(-x for x in self.data)
 76 
 77     def __contains__(self, e): # in/not in运算符重载
 78         print("__contains__()被调用")
 79         return e in self.data
 80 
 81     def __getitem__(self, i): # 重载[]取值操作
 82         return self.data[i]
 83 
 84     def __setitem__(self, i, value):#重载[]赋值操作
 85         self.data[i] = value
 86 
 87     def __delitem__(self, i): #重载[]删除操作
 88         del self.data[i]
 89 
 90 if __name__ == "__main__":
 91     L = MyList([-1, 2, -3, 4, -5])
 92     print(L[0])  # 索引取值
 93     L[2] = 333   # 通过索引设置值
 94     print(L)
 95     del L[3]     # 删除
 96     print(L)
 97 
 98     # print(2 in L)   # True
 99     # print(4 not in L) # False
100 
101     #print(-L)  # 对对象执行负号运算
102 
103     # L1 = MyList([1,3,5])
104     # L2 = MyList([1,3,5,7])
105     # print(L1 > L2)
106     # L = MyList([-1, 2, -3, 5.6789])
107     # L3 = MyList([3,4,5])
108     # print(L + L3)
109     # print(L * 2)
110     # print(2 * L)
111 
112     # print(reversed(L))  # 对象元素逆序并打印
113     # print(len(L))   # 打印返回的长度
114     # print(round(L)) # 打印新产生的对象
115     #                 # 每个元素都是原对象元素的近似值
116     # L2 = abs(L)  # 重写了__abs__()函数,支持abs表达式
117     # print(L2)  # 重写了__str__()函数,所以支持print()
my_list.py
   3)数值转换函数重写
     - int(): 重写__int__()
     - float(): 重写__float__()
     - complex(): 重写__complex__()
     - bool: 重写__bool__()
     示例见my_number.py

PYTHON1.面向对象_day02
  1 # my_number.py
  2 # 自定义数字类型
  3 # 数值转换函数重写示例
  4 class MyNumber:
  5     def __init__(self, value):
  6         self.data = value #值,字符串
  7 
  8     def __int__(self):
  9         return int(float(self.data))
 10 
 11     def __float__(self):
 12         return float(self.data)
 13 
 14     def __complex__(self):
 15         return complex(self.data)
 16 
 17 if __name__ == "__main__":
 18     num = MyNumber("123.45")
 19     print(getattr(num, "data")) # "123.45"
 20     print(num.data)  # "123.45"
 21 
 22     setattr(num, "data", "456.78")
 23     print(getattr(num, "data")) #456.78
 24 
 25     print(hasattr(num, "data")) #True
 26     print(hasattr(num, "aaaa")) #False
 27 
 28     delattr(num, "data") #删除data属性
 29     print(hasattr(num, "data")) #False
 30 
 31     # print(int(num))  #将num对象转换成int
 32     # print(float(num))
 33     # print(complex(num))
my_number.py

PYTHON1.面向对象_day02

6. 属性管理函数:操作对象属性
   1)getattr: 获取对象属性值
     - 格式: getattr(obj, name[,default])
     - 作用: getattr(x, "y") 等同于
              x.y表达式
             
   2)setattr: 设置对象属性值
     - 格式:setattr(obj, name, value)
     - 作用:setattr(x, "y", "zzz")等同于
             x.y = "zzz"表达式   
    
   3)hasattr: 判断有没有某个属性值
     - 格式:hasattr(obj, name)
     - 返回:布尔类型,有-True 没有-False
  
   4)delattr: 删除对象某个属性值
     - 格式:delattr(obj, name)
     - 作用:delattr(x, "y")等同于
             del x.y 表达式

作业:
1)编写一个账户类(Account)
    属性:账号(acct_no), 户名(acct_name),
          开户日期(reg_date),
          账户类型(acct_type)(借记卡/贷记卡),
          状态(acct_status)(正常,挂失,冻结,注销)
          余额(balance)
    方法:存款(diposite)
          取款(draw)
          冻结(freeze), 解冻(unfreeze)
          挂失(report_loss),解挂失(relieve_loss)
          修改账户信息(modify_acct_info)
2)编写测试代码

PYTHON1.面向对象_day02
  1 # account.py
  2 # 账户类
  3 dict_status = {  #状态字典
  4   0:"正常",1:"冻结",2:"挂失",3:"销户"
  5 }
  6 dict_type = {0:"借记账户", 1:"贷记账户"}
  7 
  8 class Account:
  9     def __init__(self, acct_no, acct_name,
 10                  reg_date, acct_type,
 11                  acct_status, balance):
 12         self.acct_no = acct_no #账号
 13         self.acct_name = acct_name #户名
 14         self.reg_date = reg_date #开户日期
 15         self.acct_type = acct_type #类型
 16         self.acct_status = acct_status #状态
 17         self.balance = balance #余额
 18 
 19     def diposite(self, amt): #存款
 20         print("存款前余额:%.2f"%self.balance)
 21         self.balance += amt #修改余额
 22         print("存款后余额:%.2f"%self.balance)
 23 
 24     def draw(self, amt): #取款
 25         if self.acct_status == 0: #正常
 26             if self.balance < amt: #余额不足
 27                 print("余额不足")
 28                 return
 29             else:  #余额充足
 30                 print("取款前余额:%.2f" % self.balance)
 31                 self.balance -= amt #修改余额
 32                 print("取款后余额:%.2f" % self.balance)
 33         else:  #非正常状态
 34             print("状态不允许取款")
 35 
 36     def freeze(self): # 冻结
 37         if self.acct_status != 0:
 38             print("状态不允许冻结")
 39             return
 40         self.acct_status = 1 #状态置为冻结
 41         print("账户已冻结")
 42 
 43     def unfreeze(self): #解冻
 44         if self.acct_status != 1: #判断已冻结
 45             print("状态不允许解冻")
 46             return
 47         self.acct_status = 0 #状态置为正常
 48         print("账户已解冻")
 49 
 50     def __str__(self): #重写__str__()
 51         # 将状态转换为对应的字符串
 52         status = dict_status[self.acct_status]
 53         # 将类型转换为对应的字符串
 54         type = dict_type[self.acct_type]
 55         ret="账号:%s,户名:%s,开户日期:%s,类型:%s,状态:%s,余额:%.2f"\
 56             %(self.acct_no, self.acct_name, \
 57              self.reg_date, type, \
 58              status, self.balance)
 59         return ret
 60 
 61 if __name__ == "__main__":
 62     acct = Account("6223450001", "张大大",
 63                    "2018-01-01", 0, 0, 2000.00)
 64     acct.diposite(1000.00)  #存款
 65     acct.draw(500)  #取款
 66     print(acct)  #打印账户信息
 67     acct.freeze() #冻结
 68     print(acct)  #打印账户信息
 69     acct.unfreeze() #解冻
 70     print(acct)  #打印账户信息
 71 
 72 
 73 
 74 
account.py

PYTHON1.面向对象_day02

上一篇:环境管理 pipenv 的 使用


下一篇:【python知识】 - Python3之PIPENV虚拟环境及封装