课程:Python面向对象
进度:day3
上次内容回顾
1. 多态
1)什么是多态:同一个方法,在不同
子类中有不同的表现
2)方法的重写来实现
3)保持程序的扩展性、灵活性
2. 面向对象的技术特性
1)构造方法与析构方法
a)构造:__init__()
调用时机:对象被创建时自动调用
作用:创建对象属性,并赋值
注意:子类构造方法显示调用父类构造
方法
b)析构方法:__del__()
调用时机:对象被销毁时调用
作用:对象销毁时执行清理操作
2)object类:所有类最终的父类
如果类定义时没有指定父类
默认从object中继承
__base__查看父类
3)super()和issubclass()函数
super(): 获得父类的绑定
两种格式:super() 只能在类方法中使用
super(type, obj) obj必须是type示例化的对象
issubclass():判断某个是不是另一个类的子类
格式:issubclass(cls, cls_or_tuple)
4)多重继承:一个类有多个父类
MRO: 方法解析顺序,__mro__
从下至上,从左至右
3. 函数重写:让对象操作更方便
1)对象转字符串函数
str(): __str__(),返回字符串给人阅读
repr():__repr__(),返回字符串给解释器阅读
2)内建函数
abs(): __abs__()
len(): __len__()
reversed(): __reversed()__
round():__round()__
3)数值转换函数
int(): __int__()
float(): __float__()
complex(): __complex__()
bool(): __bool__()
4. 属性操作函数
getattr(obj, name):获取对象属性
setattr(obj, name, value):设置某个属性值
hasattr(obj, name):判断对象有没有某个属性
delattr(obj, name):删除某个属性值
作业:见account.py
今天内容
1. 可迭代对象
1)什么是迭代器
2)代码特征:重写__iter__()方法返回可迭代对象
重写__next__()方法获取下一个元素
3)__next__()方法,实现迭代器协议
如果有下一个元素,则返回
如果没有下一个元素,抛出StopIteration异常
4)示例:见myiter.py
1 # myiter.py 2 # 通过函数重写,实现自定义迭代器 3 class MyIter: 4 #用列表初始化对象 5 def __init__(self, lst): 6 self.data = lst #lst是列表 7 self.cur_index = 0 #计数器 8 9 def __iter__(self):# 返回可迭代对象 10 return MyIter(self.data) 11 12 def __next__(self):# 获取下一个元素 13 if self.cur_index >= len(self.data): 14 raise StopIteration #抛出异常 15 else: 16 i = self.cur_index #记录计数器 17 self.cur_index += 1 #计数器加1 18 return self.data[i] #返回元素 19 20 if __name__ == "__main__": 21 myiter = MyIter(range(1,10)) 22 for x in myiter: 23 print(x, end=" ") 24myiter.py
2. 运算符重载
1)什么是运算重载:自定义类中,重写
某些方法,重写后就可以对对象进行
某些运算符操作
2)目的
a)简化对象操作。例如:
c = "abc" + "123"
d = "123" > "456"
b)代码清晰、直观
c)可以在类中自定义运算规则
注意:运算重载不要改变原有意义
3)算术运算符重载
- 重写方法后,支持+,-,*,//,/,%,**
- 重载方法和运算符的对应关系
__add__(self,rhs) self + rhs
__sub__(self,rhs) self - rhs
__mul__(self,rhs) self * rhs
__truediv__(self,rhs) self / rhs
__floordiv__(self,rhs) self // rhs
__mod__(self,rhs) self % rhs
__pow__(self,rhs) self ** rhs
课堂练习:在MyList类中,重载+,*运算符
L1 = MyList([1,2,3])
L2 = MyList([4,5,6])
L1 + L2==>MyList([1,2,3,4,5,6])
L1*2 ==> MyList([1,2,3,1,2,3])
见mylist.py
4)反向算术运算符重载
在正向运算符重载的函数前面加r
例如:__radd__(), __rsub__()...
支持:2 + obj (对象在操作符右边)
5)复合运算操作符
在正向运算符重载的方法前加i前缀
例如:__iadd__(), __isub__()...
重载运算符后,执行复合表达式
ojb += 2,首先查找__iadd__(),
如果没有找到,则再查找__add__(),
如果再没有找到,报TypeError异常
6)比较运算符:>,<,>=,<=,==,!=
- 重写方法和运算符的对照关系
__lt__(self, rhs) self < rhs
__gt__(self, rhs) self > rhs
__eq__(self, rhs) self == rhs
__ne__(self, rhs) self != rhs
__ge__(self, rhs) self >= rhs
__le__(self, rhs) self <= rhs
- 示例:见truck.py
1 # truck.py 2 # 卡车类,演示运算符重载 3 class Truck: 4 def __init__(self, load): 5 self.load = load #载重 6 7 def __add__(self, value):#重载+运算符 8 print("__add__()被调用") 9 return Truck(self.load + value) 10 11 def __mul__(self, value): #重载*运算符 12 return Truck(self.load * value) 13 14 #反向+运算符重载,支持 3 + truck操作 15 def __radd__(self, value): 16 print("__radd__()被调用") 17 return Truck(self.load + value) 18 19 # 符合运算符重载,支持obj += 2表达式 20 # def __iadd__(self, value): 21 # print("__iadd__()被调用") 22 # return Truck(self.load + value) 23 24 def __str__(self): 25 return "load: %d" % self.load 26 27 def __gt__(self, other): # 重载>运算符 28 print("__gt__()方法被调用") 29 if self.load > other.load: 30 return True 31 else: 32 return False 33 34 # def __lt__(self, other): # 重载<运算符 35 # if self.load < other.load: 36 # return True 37 # else: 38 # return False 39 40 if __name__ == "__main__": 41 t1 = Truck(20) 42 t2 = Truck(25) 43 print(t1 > t2) # 调用__gt__() 44 print(t1 < t2) # 调用__lt__() 45 #t = Truck(20) 46 #t2 = t + 1 # t2接受返回的对象 47 #t2 = 1 + t # 调用__radd__()方法 48 # t += 1 # 调用__iadd__()方法,如果没有该方法,调用__add__ 49 # print(t) 50 # t3 = t * 4 51 # print(t3)truck.py
- 比较规则:
>: 首先找__gt__(), 没有找__lt__()
并将执行__lt__()结果取反
如果__lt__()不存在则报错
<: 规则和大于相反
>=:首先找__ge__(), 没有找__le__()
并将执行__le__()结果取反
__le__()不存在则报错
<=:规则和大于等于相反
==:首先找__eq__(), 如果不能存在则
判断两个对象ID值,相同返回True
不同返回False
!=:首先找__ne__(),不存在则找
__eq__()并执行取反
如果__eq__()不存在则比较ID
ID相同返回False,否则返回True
课堂练习:在MyList类中,重载>,<,==,!=
操作符,比较规则如下:
等于:data属性元素个数相等
并且相同位置上的值相等
大小比较:[1,2,4] > [1,2,3]
[1,2,3,4] > [1,2,3]
[1,2,4] > [1,2,3,4]
代码见:mylist.py
7)一元运算符:带一个操作数的操作符
__neg__(self) -self 负号运算
__pos__(self) +self 正号运算
__invert__(self) ~self 取反运算
作用:重写上述方法,支持对象如下操作:
-obj, +obj, ~obj
8)in/not in运算符重载
只需要重载__contains__(self,e)
in运算,则直接调用__contains__()
not in运算,调用__contains__()取反
9)索引运算符重载:支持[]操作
__getitem__(self,i) self[i]
__setitem__(self,i,value) self[i]=value
__delitem__(self,i) del self[i]
3. 实例的内置属性
1)__dict__属性:绑定实例自身的变量字典
包括父类创建的属性和私有属性
示例:
am = AutoMobile("卡车","blue",4.0)
print(am.__dict__)
2)__class__属性:绑定创建该对象的类
作业:
1)编写一个汽车租赁程序,包含汽车类(Car),
客户类(Customer), 租车店类(CarStore),各个
类包含的属性和方法有:
Car类:
属性
car_id 车辆id号
name 车辆名称
is_lend 是否出租
price 每天单价
start_date 起租日期
end_date 租赁终止日期
方法
__str__()
Customer类:
属性
cust_id 客户编号
cust_name 客户姓名
tel_no 客户电话
方法
__str__()
CarStore类:
属性
cars 所有车辆列表
customers 所有客户列表
方法
__load_cars() 加载所有车辆信息
__load_customers() 加载所有客户信息
print_cars_info() 打印所有车辆信息
find_car() 查找车辆
add_car() 添加车辆
del_car() 删除汽车
lend() 租车
back() 还车
2)实现上述类,并编写测试代码
1 # car_store.py 2 # 汽车租赁模拟程序 3 class Car: # 车辆类 4 def __init__(self, car_id, name, 5 price, is_lend): 6 self.car_id = car_id #车辆编号 7 self.name = name #名称 8 self.price = price #价格 9 self.is_lend = is_lend #是否出租 10 self.start_date = "" #起租日期 11 self.end_date = "" #预计归还日期 12 self.cust_id = "" #租车客户编号 13 14 def __str__(self): 15 ret = "车辆编号:%s,名称:%s,单价:%.2f," \ 16 "是否出租:%s" %(self.car_id, 17 self.name, self.price,self.is_lend) 18 return ret 19 20 class Customer: #客户类 21 def __init__(self,cust_id,cust_name,tel_no): 22 self.cust_id = cust_id 23 self.cust_name = cust_name 24 self.tel_no = tel_no 25 26 def __str__(self): 27 ret = "客户编号:%s,客户名称:%s,电话:%s" \ 28 %(self.cust_id, self.cust_name, self.tel_no) 29 30 class CarStore: #租车店类 31 def __init__(self): 32 self.cars = [] #车辆列表 33 self.customers = [] #客户列表 34 self.__load_cars() #加载车辆列表 35 self.__load_customers()#加载客户列表 36 37 def __load_cars(self): #加载车辆列表 38 self.cars.append(Car("1","GOLF",400,"否")) 39 self.cars.append(Car("2","凯越",350,"否")) 40 self.cars.append(Car("3","奥迪",1200,"否")) 41 self.cars.append(Car("4","凯美瑞",800,"否")) 42 self.cars.append(Car("5","宝来",450,"否")) 43 44 def __load_cars(self): #加载车辆列表,从文件中读取 45 with open("/home/tarena/aid1805/lx/面向对象/day03/cars_list.txt") as f: 46 line = f.readline(256).replace("\n","") 47 custinfo = line.split(",") 48 car_id = custinfo[0] 49 car_name = custinfo[1] 50 price = float(custinfo[2]) 51 is_len = custinfo[3] 52 car = Car(car_id,car_name,price,is_len) 53 self.cars.append(car) #对象添加到列表 54 55 def __load_customers(self):#加载客户列表 56 cust1 = Customer("C0001","张大大","15811223344") 57 cust2 = Customer("C0002","李小小","13233333444") 58 cust3 = Customer("C0003","赵四","18044445555") 59 self.customers.append(cust1) 60 self.customers.append(cust2) 61 self.customers.append(cust3) 62 63 def print_cars_info(self): #打印车辆信息 64 for car in self.cars: #遍历车辆列表并打印 65 print(car) 66 67 def find_car(self, car_id): #根据车辆编号查询 68 for car in self.cars: #遍历车辆列表 69 if car.car_id == car_id: #编号相等 70 print(car) 71 return 72 print("未找到车辆信息") 73 return 74 75 def add_car(self, car): #添加车辆,car为Car的对象 76 if isinstance(car, Car): #car是Car类的实例 77 self.cars.append(car) 78 else: 79 print("对象类型有误") 80 #可以增加id号是否存在的逻辑判断 81 return 82 83 def del_car(self, car_id): #根据车辆编号删除 84 for car in self.cars: 85 if car.car_id == car_id: 86 self.cars.remove(car) #删除对象 87 return 88 89 def lend(self, car_id, cust_id, 90 start_date, end_date): #租车 91 for car in self.cars: 92 if car.car_id == car_id: 93 if car.is_lend == "是":#已出租 94 print("该车辆已经出租") 95 return 96 else: #未出租 97 setattr(car, "is_lend", "是")#改状态 98 setattr(car, "cust_id", cust_id) 99 setattr(car, "start_date", start_date) 100 setattr(car, "end_date", end_date) 101 print("车辆出租登记完成") 102 return 103 print("未找到车辆信息") 104 return 105 106 def back(self, car_id): #还车 107 for car in self.cars: 108 if car.car_id == car_id: 109 setattr(car, "is_lend", "否")#改状态 110 setattr(car, "cust_id", "") 111 setattr(car, "start_date", "") 112 setattr(car, "end_date", "") 113 print("还车登记完成") 114 return 115 print("未找到该车辆信息") 116 return 117 118 if __name__ == "__main__": 119 car_store = CarStore() #实例化租车店对象 120 car_store.print_cars_info() #打印车辆信息 121 print("") 122 #租车方法测试 123 car_store.lend("3","C0001","2018-01-01","2018-01-03") 124 car_store.print_cars_info() 125 126 #还车方法测试 127 car_store.back("3") 128 car_store.print_cars_info() 129 130 #添加车辆方法测试 131 car_store.find_car("3") #查找编号为3的车辆 132 133 car = Car("6","捷达",300,"否") 134 car_store.add_car(car) #将car对象添加到cars列表 135 car_store.print_cars_info()car_store.py