• 11 继承、多继承、魔术方法


    继承、多继承、魔术方法

    • 上节课作业解答

    class Rectangle(object):
        def __init__(self, width, length):
            self.width = width
            self.length = length
    ​
        # 两个方法之间留一个空行
        # 运算符后面跟一个空格
        def get_area(self):
            return self.width * self.length
    ​
        
        #类之间空两行
    rect1 = Rectangle(10, 20)
    rect1.get_area()
    print(rect1.get_area())
    ​
    # 运行结果:
    200

    一,继承

    (一)继承的使用方式
    class Rectangle(object):  #父类/基类
        def __init__(self, width, length):
            self.width = width
            self.length = length
    ​
        def get_area(self):
            return self.width * self.length
    ​
        
    class Square(Rectangle):  #继承
        pass
    ​
    square = Square(50,50)
    print(square.get_area())
    ​
    # 运行结果:
    2500# 此处Square类继承了Rectangle类 Square拥有了Rectangle里的所有方法及其属性
    # 重用代码,方便代码的管理
    (二)继承的搜索
    class Rectangle(object):
        def __init__(self, width, length):  # 实例化传参时   将初始化参数
            self.width = width
            self.length = length
    ​
        def get_area(self):
            return self.width * self.length
    ​
    ​
    class Square(Rectangle):
        def __init__(self, width, length):
            if width == length:
                Rectangle.__init__(self, width, length)  # 此处调用了父方法、这个self是正方形类的实例,不是矩形类的实例。
                super().__init__(width,length)          # 第二种调用父类的方法
            else:
                print('长度和宽度不相等,不能成为正方形')
    ​
    ​
    square = Square(25, 25)
    print(square.get_area())
    square1 = Square(25, 22)
    ​
    # 运行结果
    625
    长度和宽度不相等,不能成为正方形
    (三) __bass__ 特殊属性
    • Object最顶层的类,类的老祖宗

    • __base__ 查看继承的父类

    • __bases__ 查看继承的全部父类

      # 使用方法:
      Rectangle.__bases__
      实例.__class__.bases__

    二,多继承

    • 一个子类可以继承多个父类是多继承

    • 一层层继承下去是多重继承

    # 例1
    class Base(object):
        def func(self):
            print('这是base类')
    ​
        def func_base(self):
            print('这是func_base类')
    ​
    ​
    class A(Base):
        def func(self):
            print('这是a类')
            super().func()
    ​
        def func_a(self):
            print('这是func_a类')
    ​
    ​
    class B(Base):
        def func(self):
            print('这是b类')
            super().func()
    ​
        def func_b(self):
            print('这是func_b类')
    ​
    ​
    class C(A, B):
        def func(self):
            print('这是c类')
            super().func()
    ​
    ​
    d = C()
    d.func()
    print(C.__mro__)
    ​
    # 运行结果:
    这是c类
    这是a类
    这是b类
    这是base类
    (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>)
    ​
    # 说明 :
    # 1,C类继承了A类及B类的属性及方法
    # 2,对于A与B相同的方法func,优先继承最左边的那个
    #例2
    class Base(object):
        def func(self):
            print('这是base类')
    ​
    ​
    class Base2(object):
        def func(self):
            print('这是base2类')
    ​
        def func_base2(self):
            print('这是func_base2类')
    ​
    ​
    class A(Base):
        def func(self):
            print('这是a类')
            super().func()
    ​
        def func_a(self):
            print('这是func_a类')
    ​
    ​
    class B(Base2):
        def func(self):
            print('这是b类')
            super().func()
    ​
        def func_b(self):
            print('这是func_b类')
    ​
    ​
    class C(A, B):
        def func(self):
            print('这是c类')
            super().func()
    ​
    ​
    d = C()
    d.func()
    print(C.__mro__)
    ​
    运行结果:
    这是c类
    这是a类
    这是base类
    (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.Base'>, <class '__main__.B'>, <class '__main__.Base2'>, <class 'object'>)

    多继承 调用父类重写方法

    当子类重写父类方法之后,子类如果想再次调用父类的方法,可以使用这两种方法

    class C(A,B):
        def func(self):
        print('这是c')
        super().func()  #通过super调用
    
    class C(A,B):
        def func(self):
        print('这是c类')
        A.func(self)    #通过父类名字直接调用
    ​
    d = C()
    d.func()
    打印结果:
    这是c类
    这是a类
    这是b类
    这是base类
    
    class C(A,B):
        def func(self):
        print('这是c类')
        B.func(self)    #通过父类名字直接调用
    ​
    d = C()
    d.func()
    打印结果:
    这是c类
    这是b类
    这是base类

    使用 super调用父类重名方法,可以通过类的__mro__属性来查看多继承的情况下,子类调用父类方法时,在父类中的搜索顺序

    # 有两个用法,第一个通过类来查询,第二个通过对象来查询
    C.mro()                 # 方式一 :类名.mro()
    d.__class__.mro          # 方式二:对象.__class__.__mro__
    (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>)
    • 继承多个父类时,若想指定继承哪一个类的方法,可以重写的方式达到效果

    #例3
    class C(A, B):  # 继承A,B
        def func(self):  #覆盖父类
            B.func(self)  # 指定继承B类内的func方法
    • super()

    # 例4
    class Base(object):
        def play(self):
            print('Base is playing!')
    ​
            
    class A(Base):  # 继承Base
        def play(self):  # 自动覆盖父类的此方法
            super().play()  # 调用父类方法
            print('A is playing!')
    ​
    a = A()
    a.play()
    ​
    # 运行结果:
    Base is playing!
    A is playing!
    ​
    #说明:
    super()可自动找到父类方法
    • 类.mro() 查看继承顺序

    • 类在生成时会自动生成方法解析顺序,可以通过 类名.mro来查看

    print(C.mro())
    ​
    # 运行结果:
    [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>]
    • super()深层次用法

    • super函数可以来调用父类的方法,使用super的好处在于即使父类改变了,那么也不需要更改类中的代码

    # 例5
    class Base(object):
        def play(self):
            print('Base is playing!')
    ​
            
    class A(Base):  # 继承Base
        def play(self):  # 自动覆盖父类的此方法
            super().play()
            print('A is playing')
    ​
            
    class B(Base):  # 继承Base
        def play(self):
            super().play()
            print('B is playing')
    ​
            
    class C(A, B):  # 继承A,B
        def play(self):
            super().play()
            print('C is playing')
    ​
    c = C()
    c.play()
    print(C.mro())
    ​
    # 运行结果:
    Base is playing!
    B is playing
    A is playing
    C is playing
    [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>]
    ​
    ​
    # 说明 循根溯源执行
    由mro()可以看出,C的继承顺序为A,B,Base,object
    c在执行play()方法时,也是按此顺序执行
    1,c.play()遇到super().play(),此时压栈并溯源到A.play()
    2,在A.play()遇到super().play(),此时压栈并继续溯源到B.play()
    3,在B.play()遇到super().play(),此时压栈并继续溯源到Base.play()
    4,在Base.play()遇到print,此时执行打印:                       1# Base is playing!
    5,Base.play()执行结束,此时出栈到B.play(),在此时B中的super().paly()已经执行完成,
       紧接着遇到print,此时执行打印:                               2# B is playing
    6,B.play()执行结束,此时继续出栈到A.play(),在此时A中的super().paly()已经执行完成,
       紧接着遇到print,此时执行打印:                               3# A is playing
    7,A.play()执行结束,此时继续出栈到C.play(),在此时C中的super().paly()已经执行完成,
       紧接着遇到print,此时执行打印:                               4# C is playing
    8,运行结束。输出如上结果。

    三,魔术方法(下节课内容)

    (一)类的专有方法(目前无须理解):
    方法作用
    __init__ 构造函数,在生成对象时调用
    __del__ 析构函数,释放对象时使用
    __repr__ 打印,转换
    __setitem__ 按照索引赋值
    __getitem__ 按照索引获取值
    __len__ 获得长度
    __cmp__ 比较运算
    __call__ 函数调用
    __add__ 加运算
    __sub__ 减运算
    __mul__ 乘运算
    __div__ 除运算
    __mod__ 求余运算
    __pow__ 乘方

    (二)魔术方法之运算方法

    add(self,other)x+y
    sub(self,other) x-y
    mul(self,other) x*y
    mod(self,other) x%y
    iadd(self,other x+=y
    isub(self,other) x-=y
    radd(self,other) y+x
    rsub(self,other) y-x
    imul(self,other) x*=y
    imod(self,other) x%=y

    (三)魔术方法: __init__(self)

    class Person(object):
        def __init__(self, name, age, height):
            self.name = name               
            self.age = age
            self.height = height
    ​
        def eat(self):
            print('%s正在吃饭...' % self.name)
    ​
            
    p1 = Person('同学A', 18, 188)
    p1.eat()
    print(p1.name)
    print(p1.age)
    print(p1.height)
    ​
    # 运行结果:
    同学A正在吃饭...
    同学A
    18
    188
    • 运行p1 = Person('同学A', 18, 188)过程:

    注释过程
    实例化,产生一个类的实例 p1 = Person('同学A', 18, 188)
    python自动调用 实例.__init__(参数) p1.__init__('同学A', 18, 188)
    转换为 类.__init__(实例,参数) Person.__init__(p1,'同学A', 18, 188)

    (四)魔术方法__add__ :当类的实例之间使用 + 号时,会自动调用__add__这个魔术方法

    class Add(object):
        def __init__(self,str1):
            self.str1 = str1
    ​
        def __add__(self,other):
            return self.str1 + other.str1
    ​
    a = Add('ab')
    b = Add('cd')
    print(a + b)
    ​
    打印结果:
    abcd

    (五)字符串表示 __str____repr__

    __str____repr__原理:

    在python中,reprstr这两个方法都是用于显示的,str是面向用户的,而

    repr面向程序员。

    使用内置函数str和repr方法在处理对象的时候,分别调用的是对象的strrepr方法

    调用str函数来处理输出的对象,如果对象没有定义str方法,则调用repr方法

    调用repr函数来处理输出的对象,则调用repr处理,

    使用print操作 会首先尝试 调用str方法 ,如果str方法没有定义,则调用repr方法

    在交互模式下,输入对象 显示对象 repr方法的返回值

    例1: __str__和__repr__
    >>> class Rectangle:
        def __init__(self,length,width):
            self.length = length
            self.width = width
        def __str__(self):
            return '矩形的长:%s,矩形的宽:%s' % (self.length, self.width)
        def __repr__(self):
            return '长:%s, 宽: %s' % (self.length, self.width)
    >>> a = Rectangle(10,8)
    >>> str(a)
    '矩形的长:10,矩形的宽:8'
    >>> repr(a)
    '长:10, 宽: 8'
    例子2:只写了__str__魔术方法
    交互模式输入:a ,返回的是一个对象
                print(a):打印__str__魔术方法,返回的是内容
    >>> class Rectangle:
        def __init__(self,length,width):
            self.length = length
            self.width = width
        def __str__(self):
            return '矩形的长:%s,矩形的宽:%s' % (self.length, self.width)
    ​
        
    >>> a = Rectangle(10,8)
    >>> a
    <__main__.Rectangle object at 0x05D8FE90>
    >>> print(a)
    矩形的长:10,矩形的宽:8
    例子3:只写了__repr__魔术方法
    交互模式输入 a :返回的是调用__repr__魔术方法,返回的是内容
               print(a): 打印调用__repr__魔术方法,返回的是内容
    >>> class Rectangle:
        def __init__(self,length,width):
            self.length = length
            self.width = width
        def __repr__(self):
            return '长:%s, 宽: %s' % (self.length, self.width)
    ​
        
    >>> a = Rectangle(10,8)
    >>> a
    长:10, 宽: 8
    >>> print(a)
    长:10, 宽: 8
    
    
    例子4:__str____repr__ 魔术方法 都写上
    >>> class Rectangle:
        def __init__(self,length,width):
            self.length = length
            self.width = width
        def __str__(self):
            return '矩形的长:%s,矩形的宽:%s' % (self.length, self.width)
        def __repr__(self):
            return '长:%s, 宽: %s' % (self.length, self.width)
    ​
        
    >>> a = Rectangle(10,8)
    >>> a
    长:10, 宽: 8
    >>> print(a)
    矩形的长:10,矩形的宽:8

    说明:


    对使用者使用友好的是__str__
    向使用者提供尽可能简洁且有用的信息。让用户尽可能吸收到必要的信息。
    对开发者调试友好的是__repr__
    向开发者提供接近创建时的信息。让开发者可以直接通过复制粘贴来重建对象。

    (六) __call__方法:让类的实例可以像函数一样被调用。

    >>> class Rectangle:
        def __init__(self,length,width):
            self.length = length
            self.width = width
        def __call__(self):
            return '调用了__call__方法'>>> a = Rectangle(10,8)
    >>> a()
    '调用了__call__方法'

    (七) 类中的一些查询相关信息的方法 (了解既可)

    1、__class__   # 查看类名    
       # 格式:实例.__class__
    2、__dict__    # 查看全部属性,返回属性和属性值键值对形式
       # 格式:实例.__dict__
    3、__doc__     # 查看对象文档,即类中(用三个引号引起来的部分)
       # 格式:类名.__doc
    4、__base__    # 查看继承的父类
       # 格式:类名.__base__
    5、__bases__   # 查看继承的全部父类
       # 格式:类名.__bases__
    6、__mro__     # 查看多继承的情况下,子类调用父类方法时,搜索顺序
       # 格式:子类名.__mro__
            # 实例.class__.__mro__
     
  • 相关阅读:
    关于Web应用开发流程的总结
    package.json的所有配置项及其用法,你都熟悉么
    curl 命令行工具的使用及命令参数说明
    pytest插件探索——hook开发
    浅探前端图片优化
    使用Flask构建一个Web应用
    原生的js实现jsonp的跨域封装
    CSS定位之BFC背后的神奇原理
    webview错误
    Android 中的webview
  • 原文地址:https://www.cnblogs.com/zcmq/p/9114043.html
Copyright © 2020-2023  润新知