首页 > 其他 > 详细

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

时间:2018-05-30 23:11:14      阅读:196      评论:0      收藏:0      [点我收藏+]

继承、多继承、魔术方法

  • 上节课作业解答

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__
 

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

原文:https://www.cnblogs.com/zcmq/p/9114043.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!