Python-多态

一、在子类派生的新方法中重用父类功能的方式二

super()方法:调用super(自己的类名,self)会返回一个特殊的对象,super(自己的类名,self).属性,会参照属性发起者类的mro列表去当前所在类的父类中查找属性。

# 在python3中,会自动帮你添加super需要的两个默认参数,可省略为super()

class Student(People):
    def __init__(self,name,age,gender,stu_id,course):
        # super(Student,self).__init__(name,age,gender)
        super().__init__(name,age,gender)
        self.stu_id = stu_id
        self.course = course

两个小练习,加深super的查找顺序:

class A:
    def test(self):
        super().test()
class B:
    def test(self):
        print('from B')
class C(A,B):
    pass

c=C()
print(C.mro())
c.test()
--------------------
'''
问:是否会报错?
答案:不会报错,因为属性的查找发起者是C不是A,C的mro列表中,查找顺序为C-A-B,所以A中没有会去B中找,能找到。
虽然A与B没有继承关系,但是因为发起者是C,虽然在A中才使用super方法,但依然会去B中找
'''
class A:
    def test(self):
        print('A---->test')
        super().aaa()
class B:
    def test(self):
        print('B---->test')

    def aaa(self):
        print('B---->aaa')

class C(A,B):
    def aaa(self):
        print('C----->aaa')

c=C()
print(C.mro())
c.test()
------------------------
'''
问:结果是什么?
答案:
A---->test
B---->aaa
查找顺序是按照查找发起者的mro列表,但是在super查找时,会从当前类的下一个类中找,在本题中,supper在A中,根据mro列表,查找顺序为C-A-B-Object,所以去B中找到了
'''

练习三,加深super()所传对象理解,我们知道super()自动帮我们传了super(自己的类名,self)

class A: 
	def x(self):
		print('run A.x')
		super().x()
		print(self)

class B:
	def x(self):
		print('run B.x')
		print(self)
		
class C(A,B):
	def x(self):
		print('run C.x')
		super().x()
		print(self)

C().x()

二、组合(表达了什么有什么的关系)

组合:把另外一个类的对象赋值给当前对象的属性

class Teacher:
    def __init__(self, name, age, gender, level):
        self.name = name
        self.age = age
        self.gender = gender
        self.level = level

    def tell(self):
        print("%s:%s" % (self.name, self.age))


class Student:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender


class Course:
    def __init__(self, name, price, period):
        self.name = name
        self.price = price
        self.period = period

    def tell(self):
        print('<%s:%s:%s>' % (self.name, self.price, self.period))


tea1 = Teacher("egon", 18, "male", 10)
stu1 = Student("xxx", 19, "male")

python = Course("python开放", 30000, "3mons")
linux = Course("linux课程", 30000, "3mons")

tea1.courses = [python,linux]
stu1.course = python

三、多态

多态:同一种事物有多种形态
例如:动物就有多种形态,如人,猫,狗等
特性,我们可以在不考虑某一个对象的具体类型情况下直接使用对象
举例:事物有多个形态

利用abc模块下的abstractmethod,可以强制继承了本类的子类必须实现本类的方法。可以只写一个pass,但必须要写这个方法

import abc
class File(metaclass=abc.ABCMeta): #同一类事物:文件
    @abc.abstractmethod
    def click(self):
        pass

class Text(File): #文件的形态之一:文本文件
    def click(self):
        print('open file')

class ExeFile(File): #文件的形态之二:可执行文件
    def click(self):
        print('execute file')

应用:

# 假设我们已经定义了People,Dog,Pig三个类

peo=People()
dog=Dog()
pig=Pig()

#peo、dog、pig都是动物,只要是动物肯定有talk方法
#于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
peo.talk()
dog.talk()
pig.talk()

#更进一步,我们可以定义一个统一的接口来使用
def func(obj):
    obj.talk()

若想通过父类控制子类:

'''
通过abc模块,我们可以控制子类必须实现父类的方法,若无父类的方法就会报错。
'''
# 父类有的功能,子类一定有
import abc

class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def speak(self):
        pass

    @abc.abstractmethod
    def run(self):
        pass

# Animal()  # Animal的作用是用来制定标准的

class People(Animal):
    def speak(self):
        print("啊啊啊啊")

    def run(self):
        print("咻咻咻...")

class Dog(Animal):
    def giao(self):
        print("汪汪汪")

class Pig(Animal):
    def heheng(self):
        print("哼哼哼")

peo1=People()
d1=Dog()
p1=Pig()

peo1.jiao()
d1.giao()
p1.heheng()

此时的Animal类是无法实例化的,此时的作用仅仅是为了制定标准。虽然我们通过父类对子类施加了编写限制,但是此时Animal类仅仅只是为了制定标准而存在,我们付出了继承一个类的代价,然而我们完全可以自己私下约定好,每个类中必须有的标准,同样能够实现这个效果,所以更推荐私下约定,因为继承越多,程序的耦合就越重。
自己私下约定好,减少耦合,就是鸭子类型

四、python一切皆对象

python当中使用的所有方法,都是实例化出来的方法,也就是对象,我们在pycharm中使用方法时,代码提示会有一个self的参数,其实就是对象,从我们学习python开始,就在使用对象。对于python一切皆对象的文章有很多,也有很多的例子,长篇大论容易使人搞懵。其实在我们了解了对象之后,就可以理解我们之前使用的python内置方法的原理了。

五、面向对象高级(就是一堆内置方法)

可前往该博客查看常用的方法:
https://www.cnblogs.com/linhaifeng/articles/6204014.html

六:反射

反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)

对于任意一个类,都可以知道这个类的所有属性和方法;
对于任意一个对象,都能够调用他的任意方法和属性。
这种动态获取程序信息以及动态调用对象的功能称为反射机制。

在python中实现反射非常简单,在程序运行过程中,如果我们获取一个不知道存有何种属性的对象,若想操作其内部属性,可以先通过内置函数dir来获取任意一个类或者对象的属性列表,列表中全为字符串格式

class People:
    def __init__(self,name,age,gender):
        self.name=name
        self.age=age
        self.gender=gender

obj=People('egon',18,'male')
dir(obj) # 列表中查看到的属性全为字符串
------------------
[......,'age', 'gender', 'name']

接下来就是想办法通过字符串来操作对象的属性了,这就涉及到内置函数hasattr、getattr、setattr、delattr的使用了(Python中一切皆对象,类和对象都可以被这四个函数操作,用法一样)

lass Teacher:
    def __init__(self,full_name):
        self.full_name =full_name

t=Teacher('Egon')

# hasattr(object,'name')
hasattr(t,'full_name') # 按字符串'full_name'判断有无属性t.full_name

# getattr(object, 'name', default=None)
getattr(t,'full_name',None) # 等同于t.full_name,不存在该属性则返回默认值None

# setattr(x, 'y', v)
setattr(t,'age',18) # 等同于t.age=18

# delattr(x, 'y')
delattr(t,'age') # 等同于del t.age
posted @ 2020-12-01 09:29  王寄鱼  阅读(158)  评论(0编辑  收藏  举报