zoukankan      html  css  js  c++  java
  • 面向对象三大特性之多态以及面向对象进阶

    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管理的是对象的生命周期,会在对象销毁时执行清理

     23

  • 相关阅读:
    Java构造和解析Json数据的两种方法详解一
    使用json-lib进行Java和JSON之间的转换
    java 读取文件转换成字符串
    Jackson 框架,轻易转换JSON
    (转载)最黑的黑客米特尼克:多次耍FBI 终被高手擒
    (转载)Linux下IPTABLES防火墙的设定
    (转载)Linux下IPTABLES配置详解
    (转载)Linux上iptables防火墙的基本应用教程
    (转载)更好的重启nginx 服务器
    (转载)JavaScript中的Window窗口对象
  • 原文地址:https://www.cnblogs.com/sxchen/p/11266754.html
Copyright © 2011-2022 走看看