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__
 
posted @ 2018-05-30 22:44  开心每一天q  阅读(133)  评论(0编辑  收藏  举报