单继承、多继承下的属性查找、super关键字、多态与多态性、组合

单继承下的属性查找

单继承:一个类只能继承一个类。

class C():
pass
class B(C):
    pass
class A(B): # 单继承
    pass

单继承下的属性查找顺序:

  先从对象本身的名称空间中查找 ------> 产生这个对象的类中去查找 ------>继承的父类中去查找

# 查找属性
class Foo():
    def f1(self):
        print('from f1')

    def f2(self):
        print('from f2')
        self.f1() # 此时,self = obj,所以调用Bar中的方法'f1'

class Bar(Foo): # 单继承,继承Foo的所有属性
    def f1(self):
        print('from Bar')

obj = Bar() # 调用Bar产生一个 obj对象
obj.f2()  # obj.f2() = obj.f2(obj)  # from f2
                                    # from Bar

练习题

class Foo():
    def __f1(self): # 隐藏方法 _Foo__f1
        print("Foo.f1")

    def f2(self):
        # obj:
        print("Foo.f2")
        self.__f1() # self._Foo__f1()

class Bar(Foo):
    def __f1(self):
        print("Bar.f1")
obj = Bar()
obj.f2()  # obj.f2(obj) # Foo.f2
                        # Foo.f1

多继承下的属性查找

多继承:一个类可以继承多个类,从左往右依次查找(python中支持多继承)

class D():
    pass
class C(D):
    pass
class B(C,D):
    pass
class A(B,C,D):
    pass

多继承下的属性查找分为:菱形查找、非菱形查找

非菱形查找:按照一个分支一个分支的查找

菱形查找:

  经典类:按深度优先查找。

  深度查找:就是从左往右依次查找,从第一个的分支直接找到顶点。

  新式类:按广度优先查找。

  广度查找:从左往右依次查找,从最后一个分支直接找到顶点。

# 多继承下的属性查找
class F():
    def f(self):
        print('from F')
class E():
    def f(self):
        print('from E')
class D(F):
    def f(self):
        print('from D')
class C(E):
    ...
    # def f(self):
    #     print('from C')
class B():
    ...
    # def f(self):
        # print('from B')
class A(B,C,D):
    # def f(self):
        # print('from A')
    ...
obj = A()
print(A.mro()) # mro 打印出查找顺序
# 查找顺序:[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.E'>, <class '__main__.D'>, <class '__main__.F'>, <class 'object'>]
obj.f() # from E
# 广度查找
class G(object):
    def test(self):
        print('from G')
class E(G):
    def test(self):
        print('from E')
class F(G):
    def test(self):
        print('from F')
class B(E):
    def test(self):
        print('from B')
class C(F):
    def test(self):
        print('from C')
class D(G):
    def test(self):
        print('from D')
class A(B, C, D):
    # def test(self):
    #     print('from A')
    pass

obj = A()
print(A.mro())  # 打印A类的mro顺序
# [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class '__main__.G'>, <class 'object'>]

在python3 中都是新式类,所以多继承下的属性查找,如果属性查找不到,按广度优先的方式继续查找。

一般情况下,最好不使用多继承。

super关键字

super关键字的使用:当方法中出现super()关键字的时候,就使用mro列表来查找属性。

super的使用是依赖于继承的,查找顺序遵循mro列表,每个类的mro列表都不一样,但是都是从起始类开始的。

# super关键字的使用
class A():
    def f(self):
        super().f() #在A没有继承B的时候,继续按照mro列表继续往后走

class B():
    def f(self):
        super().f() # 在B类没有继承C类,继续往下执行
class C():
    def f(self):
        print('C')

class D(A,B,C):
    pass

obj = D()
print(D.mro()) #[<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>]
obj.f()  # C

多态与多态性

多态:一种事物的多种形态

多态性:多态带来的特性,就是在不考虑对象的类型的情况下,直接调用对象的方法。

多态性的例子:

def len():
    return obj.len()
len('123')
len([1,2,3])
len({'a':1})
len((1,2,3))
# 鸭子类型
鸭子类型:更多的是关注对象的行为,不管对象是什么类型的。
class People(): def speak(self): print('People') class Cat(): def speak(self): print('Cat') class Dog(): def speak(self): print('Dog') class Flower(): def f(self): print('Flower') obj = People() obj1 = Cat() obj2 = Dog() obj3 = Flower() # 定义一个功能用来执行共有的功能 def Animal(obj): return obj.speak() Animal(obj) #People Animal(obj1) #Cat Animal(obj2) #Dog Animal(obj3) # 没有speak这个功能所以会报错 AttributeError: 'Flower' object has no attribute 'speak'

强制限制(不推荐):

  通过在父类导入 abc模块,将类抽象化,从而限制子类必须要有某些方法。

抽象类:在父类中限制子类的行为。

抽象类的特点:只能被继承,不能被实例化。抽象类中的方法都是抽象方法,抽象方法不会实现具体的功能,只是用来限制子类的行为。

# 强制限制
import abc
class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod # 该装饰器限制子类必须定义有一个名为talk的方法
    def speak(self):  # 抽象方法中无需实现具体的功能
        pass
    def eat(self):
        pass

class cat(Animal):
    def speak(self):
        print('cat speak miao')
    def eat(self):
        print('cat eat fish')
class pig(Animal):
    def sleep(self):
        print('pig always sleep')
obj = cat()
# 若子类pig中没有一个名为talk的方法则会抛出异常TypeError,无法实例化。
obj1 = pig()  # TypeError: Can't instantiate abstract class pig with abstract methods speak
obj.speak() # cat speak miao
obj.eat() # cat eat fish
# pig 类中没有speak方法,而在父类Animal中speak方法被抽象化了,所以子类中必须要定义speak方法
# obj1.sleep() # TypeError: Can't instantiate abstract class pig with abstract methods speak

组合

组合:就是一个对象拥有一个属性,该属性的值是另外一个对象

class Foo():
    def __init__(self,m):
        self.m = m
class Bar():
    def __init__(self,n):
        self.n = n
obj = Foo(10)
obj1 = Bar(20)
obj.x = obj1  # 组合,此时的obj就是一个超级对象,通过一个对象得到另外一个对象的值
print(obj.x.n) # obj.x 就是 obj1  结果为:20
class People():
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

"""
继承一般用在什么是什么的时候
组合一般用在什么有什么的时候
"""
class Course():
    def __init__(self, course_name, course_price, course_period):
        self.course_name = course_name
        self.course_price = course_price
        self.course_period = course_period

python=Course("python", 10000, '6mon')
linux = Course("linux", 20000, '5mon')
# print(python.course_name) # python


class Student(People):
    def __init__(self, name, age, gender, course=None):
        if course is None:
            course = []
        super().__init__( name, age, gender) # 调用People里的__init__
        self.courses = course
    def choose_course(self):
        pass


stu = Student('kevin', '19', 'male')

stu.courses.append(python) # stu.courses ====> [python对象]
stu.courses.append(linux) # stu.courses ====> [python对象, linux对象]
print(stu.courses) # [<__main__.Course object at 0x00000149EE630940>, <__main__.Course object at 0x00000149EE630A20>]
for i in stu.courses:
    print(i.course_name)
    print(i.course_price)
# 结果为:
# python
# 10000
# linux
# 20000

 

posted @ 2023-06-27 20:25  Maverick-Lucky  阅读(36)  评论(0)    收藏  举报