Day23 三大特性之多态以及面向对象进阶

1.多态

概念:一种事物具备多种不同的形态

例如:水有三种形态

面向对象中的多态:多个不同类对象可以响应同一个方法,产生不同的结果

多态不是一种特殊的语法,而是一种状态,特性(多个对象有相同的使用方法)

优点:对于使用者,可以降低使用难度

 

实现多态

接口,抽象类,鸭子类型都可以实现多态,最简单的就是鸭子类型

鸭子类型实现多态例子

 1 # 鸭子类型产生几个类
 2 class Ji:
 3     def bark(self):
 4         print('咕咕咕')
 5 
 6     def spawn(self):
 7         print('下鸡蛋')
 8 
 9 class Duck:
10     def bark(self):
11         print('嘎嘎嘎')
12 
13     def spawn(self):
14         print('下鸭蛋')
15 
16 
17 class E:
18     def bark(self):
19         print('鹅鹅鹅')
20 
21     def spawn(self):
22         print('下鹅蛋')
23 
24 # 定义一个调用他们的方法
25 def manage(obj):
26     obj.bark()
27     obj.spawn()
28 
29 j = Ji()
30 y = Duck()
31 e = E()
32 
33 manage(j)  # 多个不同的对象都可以使用manage的方法,产生不同的结果
34 manage(y)
35 manage(e)

在python中许多内置方法也是多态的表现形式

1 # python中很多内置方法也是多态的表现形式
2 a = 1
3 b = 'sxc'
4 c = [1,5,'xxx']
5 # type,不同的对象拥有相同的方法,print其实也是多态的表现
6 print(type(a))
7 print(type(b))
8 print(type(c))

 

2.OOP相关的内置函数

(1)isinstance(obj,cls)

检查是否obj是类cls的对象,判断一个对象是否是某个类的实例

 1 # isinstance(obj,cls)
 2 class Person:
 3     def __init__(self,name,age):
 4         self.name = name
 5         self.age = age
 6 
 7 p1 = Person('sxc',18)
 8 
 9 p2 = ('sxc',18)
10 
11 print(isinstance(p1,Person))  # 判断是否是该类的对象
12 print(isinstance(p2,Person))
13 
14 print(isinstance(p2[0],str))  # 还可以判断是否为基本类型,p2的第一个参数是'sxc'
15 print(isinstance(p2[1],int))  # p2的第二个参数是18,是int类型

(2)issubclass(sub,super)

 检查sub类是否是super的子类(派生类),判断一个类是否是另一个类的子类

 1 # issubclass(sub,super)
 2 class Animal:
 3     def __init__(self,name,age):
 4         self.name = name
 5         self.age = age
 6 
 7 class Person(Animal):
 8     def speak(self):
 9         print('人说话')
10 
11 class Student(Person):
12     def study(self):
13         print('学生学习')
14 
15 class Dog(Animal):
16     def bark(self):
17         print('狗叫')
18 
19 print(issubclass(Student,Animal))  # 判断是否为某一个类的子类
20 print(issubclass(Dog,Animal))  #
21 print(issubclass(Student,Person))  #
22 print(issubclass(Dog,Person))  #

3.类中的魔法函数

(1)__str__

执行时机:会在对象被转换成字符串时执行,转换的结果就是这个函数的返回值

使用场景:可以利用该函数来自定义对象的打印格式

 1 # __str__
 2 class Person:
 3     def __init__(self,name,age):
 4         self.name = name
 5         self.age = age
 6 
 7     def __str__(self):  # 自定义对象的打印格式
 8         return '姓名:%s,年龄:%s'%(self.name,self.age)
 9 
10 p1 = Person('sxc',18)
11 print(p1)  # 如果没有__str__函数返回值是该对象的内存地址.<__main__.Person object at 0x000001C339547278>
12 print(p1)  # 利用该函数获取自己想要的返回值.姓名:sxc,年龄:18

作业:1.编写class类,拥有name,teacher,cursor三个属性,自定义打印格式输出,对象的全部属性

 1 class School:
 2     def __init__(self,name,teacher,course):
 3         self.name = name
 4         self.teacher = teacher
 5         self.course = course
 6 
 7     def __str__(self):
 8         return '学校名:%s,老师名:%s,课程名:%s'%(self.name,self.teacher,self.course)
 9 
10 s1 = School('oldboy','tank','python10期')
11 print(s1)
自定义打印格式输出

(2)__del__析构函数

执行时机:手动删除对象时立马执行,或是程序运行结束时也会执行

使用场景:当对象在使用过程中,打开了不属于解释器的资源:例如文件,网络端口等

 1 # __del__
 2 class FileTool:
 3     def __init__(self,path):
 4         self.file = open(path,'r',encoding='utf-8')
 5 
 6     def read(self):  # 打开文件之后py解释器不会主动的关闭文件
 7         return self.file.read()
 8 
 9     def __del__(self):  # 该方法在程序运行完毕之后自动执行
10         self.file.close()  # 通过上述条件,确定我们不再复用该文件,可以在这关闭文件
11         print('关闭文件')  # 证明程序最后会执行该方法
12 
13 tool = FileTool('a.txt')
14 print(tool.read())

(3)__call__

执行时机:在调用对象时自动执行(即对象名加括号)

 1 # __call__
 2 class A:
 3     def __call__(self, *args, **kwargs):  # 在调用对象时执行
 4         print('运行call')
 5         print(args)  # 调用对象时传入的参数,单个参数
 6         print(kwargs)  # 传入的字典类型
 7 
 8 a = A()
 9 # a()
10 # a(18)
11 a(18, name = 'sxc')  # 对象名+()自动触发

(4)__slots__优化内存

该属性是一个类属性,用于优化内存占用

优化的原理:将原本不固定的属性数量变的固定,从而达到减少内存开销的效果

需要注意的是这个方法会把__dict__都取消,并且当使用这个方法时,将导致这个类的对象无法添加新的属性

 1 # __slots__
 2 import sys
 3 
 4 class A:
 5     __slots__ = ['name']  # 在声明属性时使用,中括号内的就是生成的属性,
 6     # 并且只会产生括号中属性的名称空间
 7 
 8     def __init__(self,name):
 9         self.name = name
10         print(name)
11         # print(self.__dict__)  # 内部也不能查看
12 
13 a = A('sxc')
14 
15 # print(a.__dict__)  # 使用该方法时__dict__也被取消,会报错
16 # a.age = 18  # 并且不能添加新的属性
17 
18 print(sys.getsizeof(a))  # 查看对象的内存占用,当没有__slots__方法时为56
19 print(sys.getsizeof(a))  # 查看对象的内存占用,有该方法时为48,内存确实被优化了

4.点. 括号[]语法的实现原理

(1)点.语法的实现原理(getattr,setattr,delattr)

getattr:用点访问属性时,如果属性不存在则执行

setattr:用点设置属性时执行

delattr:用del 对象.属性, 删除属性时执行

getattribute:该函数也是用来获取属性

在获取属性时,如果存在getattribute则先执行该函数,如果没有返回值,则再执行getattr,如果有返回值,则直接返回

 1 # 点属性的实现原理getattr,setattr,delattr,getattribute
 2 class A:
 3     def __getattr__(self, item):  # 该函数有返回值
 4         print('执行了__getattr__')
 5         return '__getattr__的返回值'  # 该返回值只有属性没有返回值才会执行
 6 
 7     def __setattr__(self, key, value):
 8         print('执行了__setattr__')
 9         self.__dict__[key] = value  # 这就是点设置值语法的实现原理
10 
11     def __delattr__(self, item):
12         print('执行了__delattr__')
13         self.__dict__.pop(item)  # 这就是点删除值语法的实现原理
14 
15     def __getattribute__(self, item):
16         # print('__getattribute__')
17         return super().__getattribute__(item)  # 这就是点获取值语法的实现原理
18 
19 a = A()
20 
21 # 点语法内部是调用__dict__进行增删查改的操作
22 a.name = 'sxc'  # 执行了setattr
23 # print(a.name)  # 执行了getattr,并且有返回值
24 print(a.name)  # 当有两个get方法时会先执行getattribute,没有返回值的情况下再执行getattr
25 del a.name  # 执行了delattr
26 
27 print(a.xxx)  # 属性不存在的情况下执行getattr

点语法的实现原理是在上述方法里__dict__里加入新的值

(2)括号[]语法的实现原理(getitem,setitem,delitem)

getitem:当用中括号去获取属性时执行

setitem:当用中括号去设置属性时执行

delitem:当用中括号去删除属性时执行

 1 # 括号语法的实现原理
 2 class A:
 3     def __getitem__(self, item):
 4         print('__getitem__')
 5         return self.__dict__[item]  # 这就是括号获取值语法的实现原理
 6 
 7     def __setitem__(self, key, value):
 8         print('__setitem__')
 9         self.__dict__[key] = value  # 这就是括号设置值语法的实现原理
10 
11     def __delitem__(self, key):
12         print('__delitem__')
13         self.__dict__.pop(key)  # 这就是括号删除值语法的实现原理
14 
15 
16 a = A()
17 a['name'] = 'sxc'  # 可以括号赋值
18 print(a['name'])  # 可以括号取值
19 del a['name']  # 可以括号删值

可以使用点语法又可以使用括号语法

 1 classes = {}
 2 class Student(dict):
 3     def __getattr__(self, item):
 4         return self.get(item)
 5 
 6     def __setattr__(self, key, value):
 7         self[key] = value
 8 
 9     def __delattr__(self, key):
10         del self[key]
11 
12 s1 = Student()
13 s1['name'] = 'zzp'
14 print(s1.name)
15 
16 s1.age = 28
17 print(s1['age'])
18 
19 s1['classes'] = 'py10期'
20 print(s1.classes)

 

5.运算符重载

当我们在使用某个符号时,python解释器都会为这个符号定义一个含义,同时调用对应的处理函数,当我们需要自定义对象的比较规则时,就可以在子类中覆盖大于 等于 小于等一系列的方法

 1 class Student:
 2     def __init__(self,name,age,height,weight):
 3         self.name = name
 4         self.age = age
 5         self.height = height
 6         self.weight = weight
 7 
 8     def __gt__(self, other):  # 大于
 9         return self.age > other.age
10 
11     def __lt__(self, other):  # 小于
12         return self.height < other.height
13 
14     def __eq__(self, other):  # 等于
15         return self.weight == other.weight
16 
17 s1 = Student('sxc',18,175,60)
18 s2 = Student('zzj',20,174,60)
19 
20 
21 print(s1 > s2)  # 比较年龄
22 print(s1 < s2)  # 比较身高
23 print(s1 == s2)  # 比较体重

 作业2:创建一系列student对象存储到列表中, 然后编写排序算法,将对象按照年龄排序,排序算法不限

 1 # 运算符重载
 2 # 创建一系列student对象存储到列表中, 然后编写排序算法,将对象按照年龄排序,排序算法不限
 3 class Student:
 4     def __init__(self,name,age,height,weight):
 5         self.name = name
 6         self.age = age
 7         self.height = height
 8         self.weight = weight
 9 
10     def __gt__(self, other):  # 大于
11         return self.age > other.age
12 
13     def __lt__(self, other):  # 小于
14         return self.age < other.age
15 
16     def __eq__(self, other):  # 等于
17         return self.weight == other.weight
18 
19 s1 = Student('sxc',18,175,60)
20 s2 = Student('zzj',20,174,60)
21 s3 = Student('zzp',21,156,50)
22 s4 = Student('lzx',17,156,50)
23 s5 = Student('zkj',25,156,50)
24 
25 # print(s1 > s2)  # 比较年龄
26 # print(s1 < s2)  # 比较身高
27 # print(s1 == s2)  # 比较体重
28 
29 
30 all_student = []
31 all_student.append(s1)
32 all_student.append(s2)
33 all_student.append(s3)
34 all_student.append(s4)
35 all_student.append(s5)
36 
37 for i in range(len(all_student)):
38     for j in range(i+1,len(all_student)):
39         if all_student[i] > all_student[j]:
40             all_student[i],all_student[j] = all_student[j],all_student[i]
41 
42 for i in all_student:
43     print(i.name)
按照年龄排序

6.迭代器协议

迭代器指的是具有__iter__和__next__的对象

我们可以为对象增加这两个方法来让对象变成一个迭代器

 1 # 迭代器
 2 class MyIter:
 3     def __init__(self,num):  # num用来限制迭代次数
 4         self.num = num
 5         self.c = 0
 6 
 7     def __iter__(self):
 8         return self
 9 
10     def __next__(self):
11         if self.c < self.num:  # 加上逻辑判断来限制迭代次数
12             self.c += 1
13             return '123'
14         else:
15             raise StopIteration
16 
17 for i in MyIter(10):
18     print(i)

自定义编写一个range方法

 1 # 实现一个自定义的range
 2 class Myrange:
 3     def __init__(self,start, end, step):
 4         self.start = start  # 开始值
 5         self.end = end  # 结束值
 6         self.step = step  # 步长
 7 
 8     def __iter__(self):
 9         return self
10 
11     def __next__(self):
12         a = self.start  # 使得self.start能正常递增
13         self.start += self.step
14         if a < self.end:
15             return a
16         else:
17             raise StopIteration
18 
19 for i in Myrange(1,10,2):
20     print(i)

7.上下文管理

指的是一段话的意义,要参考当前的场景,即上下文

在python中,上下文可以理解为一个代码区间,例如with open打开的文件仅在这个上下文中有效

两个方法

enter:表示进入上下文

exit:表示退出上下文

当执行with语句时,会先执行enter,当代码执行完毕后执行exit,或者代码遇到异常会立即执行exit,并传入错误信息

包含错误的类型,错误的信息,错误的追踪信息

 1 class Myopen:
 2     def __init__(self,path):
 3         self.path = path
 4 
 5     def __enter__(self):
 6         print('__enter__')
 7         self.file = open(self.path)
 8         return self  # 需要返回自己
 9 
10     def __exit__(self, exc_type, exc_val, exc_tb):
11         print('__exit__')
12         self.file.close()
13         return True  # 返回错误有没有处理
14 
15 with Myopen('a.txt') as m:
16     print(m.file.read())

注意:

enter函数应该返回对象自己

exit函数可以有返回值,是一个bool类型,用于表示异常是否被处理,仅在上下文中出现异常有用,如果为True,则表示异常被处理了,False表示异常未被处理,程序将中断报错.

与del的区别:

  上下文关联,管理的是一个代码范围,出了范围自动清理

  del管理的是对象的生命周期,会在对象销毁时执行清理

猜你喜欢

转载自www.cnblogs.com/sxchen/p/11266754.html
今日推荐