课程: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="")
24
myiter.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