python面向对象(part4)--多态及设计原则

学习笔记
开发工具:Spyder

文章目录

多态

  • 定义

父类的同一种动作或者行为,在不同的子类上有不同的实现。

  • 作用

①继承将相关概念的共性进行抽象,多态则在共性的基础上,体现类型的个性化(一个行为有不同的实现)。
②增强程序扩展性,体现开闭原则。

备注:开闭原则为对扩展开放,对修改关闭。

例子(判断哪些情况是多态)

类代码:

class Weapon:
    """ 武器 """
    def __init__(self,atk):
        self.atk = atk

    def buy(self):
        print("购买武器")

    def attack(self):
        # 子类如果没有当前方法,就会报错
        raise  NotImplementedError()


class Gun(Weapon):
    """ 枪 """
    def __init__(self,atk,speed):
        super().__init__(atk)
        self.att_speed = speed

    def attack(self):
        print("开枪")

class Grenade(Weapon):
    """ 手雷 """

    def __init__(self, atk, range):
        super().__init__(atk)
        self.explode_range = range

    def attack(self):
        print("爆炸")

问:下面这两段代码,体现了多态么?

g01 = Gun(10, 1)
g01.buy()
g01.attack()
gren01 = Grenade(30, 5)
gren01.buy()
gren01.attack()

答:都没有,多态要求调用父类,执行子类,以上两段代码都是调用子类,所以均不是多态。

那什么时候才是多态呢?看下面一段代码:

g01 = Gun(10, 1)

def my_use(weapon):
    weapon.attack() #调用父类

my_use(g01) #执行子类

在这里,我们定义了一个my_use()方法。
在my_use()方法中,我们想要用父类的实例对象weapon来调用attack()方法,但实际上传入的参数为子类实例对象g01,所以在执行时,执行的是子类的attack()方法。这时,就满足了多态的要求,即调用父类,执行子类。这里的调用父类,即我们认为的观念上的父类,但实际传入的实例对象为子类的实例对象。

PS:个人理解,若有错误,请求指出。

重写

子类实现了父类中相同的方法(方法名、参数),在调用该方法时,实际调用的是子类的方法。

内置可重写函数

在python中,以双下划线开头,并以双下划线结尾的是,系统定义的成员。我们可以在自定义类中进行重写,进而改变其行为。
比如:
__str__函数:将对象转换为字符串(对人友好的)
__repr__函数:将对象转换为字符串(解释器可识别的)

举个例子1(__str__函数)

代码:

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


class BunnyB:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def __str__(self):
        return "我叫%s,我是一只%d个月大的兔兔" % (self.name, self.age)

b0A = BunnyA("大白", 8)
print(b0A)

b0B = BunnyB("小黄", 7)
print(b0B)

结果:
《python面向对象(part4)--多态及设计原则》

举个例子2(__repr__函数)

代码:

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



class BunnyB:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def __str__(self):
        #返回给人看
        return "我叫%s,我是一只%d个月大的兔兔" % (self.name, self.age)
    
    def __repr__(self):
        #返回给解释器看
        return "BunnyB('%s', %d)" % (self.name, self.age)


b0A = BunnyA("大白", 8)
print(b0A)
print(b0A.__repr__())
print("-----------------")

b0B = BunnyB("小黄", 7)
print(b0B)
print(b0B.__repr__())
print("-----------------")

b0B2 = eval(b0B.__repr__())
print(b0B2)

结果:
《python面向对象(part4)--多态及设计原则》

备注:eval()函数,可以在其中放入字符串(python代码的字符串),然后执行。

举个例子

《python面向对象(part4)--多态及设计原则》

运算符重载

运算符重载可以让自定义的类生成的对象(实例)能使用运算符进行操作。

算数运算符(对象在运算符左边)

《python面向对象(part4)--多态及设计原则》

例子(对象 + #)

代码:

class Vector:

    def __init__(self, x):
        self.x = x

    def __str__(self):
        return "向量的x变量是:%s"%self.x

    # 对象 +
    def __add__(self, other):
        return Vector(self.x + other)

v01 = Vector(10)
v02 = v01 + 5
print(v02)

结果:

《python面向对象(part4)--多态及设计原则》

反向算数运算符重载(对象在运算符右边)

《python面向对象(part4)--多态及设计原则》

例子(# + 对象)

代码:

class Vector:

    def __init__(self, x):
        self.x = x

    def __str__(self):
        return "向量的x变量是:%s"%self.x

    # 对象 +
    def __add__(self, other):
        return Vector(self.x + other)

    # + 对象
    def __radd__(self, other):
        return Vector(self.x + other)

v01 = Vector(10)
v02 = 1 + v01
print(v02)

结果:
《python面向对象(part4)--多态及设计原则》

复合运算符

《python面向对象(part4)--多态及设计原则》

运用反向算数运算符来实现【+=】会创造新的对象,若我们不希望创建新的对象,且在原有对象上实现【+=】,则可以用复合运算符

例子(对象 += #)

代码:

class Vector:

    def __init__(self, x):
        self.x = x

    def __str__(self):
        return "向量的x变量是:%s"%self.x

    # 对象 +
    def __add__(self, other):
        return Vector(self.x + other)

    # + 对象
    def __radd__(self, other):
        return Vector(self.x + other)

    # 累加:在原有对象基础上进行操作,不创建新对象.
    def __iadd__(self, other):
        self.x += other
        return self

v01 = Vector(10)
print(id(v01))
v01 += 1
print(v01)
print(id(v01))

结果:
《python面向对象(part4)--多态及设计原则》

比较运算符重载

《python面向对象(part4)--多态及设计原则》

例子

代码:

class Vector:

    def __init__(self, x):
        self.x = x

    def __str__(self):
        return "向量的x变量是:%s"%self.x

    # 对象 +
    def __add__(self, other):
        return Vector(self.x + other)

    # + 对象
    def __radd__(self, other):
        return Vector(self.x + other)

    def __lt__(self, other):
        return self.x  < other

v01 = Vector(10)
print(v01 < 5)

结果:

《python面向对象(part4)--多态及设计原则》

设计原则

设计原则

对扩展开放,对修改关闭。
增加新功能,不改变原有代码。

类的单一职责

一个类有且只有一个改变它的原因。

依赖倒置

客户端代码(调用的类)尽量依赖(使用)抽象的组件。
抽象的是稳定的。实现是多变的。

组合复用原则

如果仅仅为了代码复用优先选择组合复用,而非继承复用。
组合的耦合性相对继承低。

里氏替换

父类出现的地方可以被子类替换,在替换后依然保持原功能。
子类要拥有父类的所有功能。
子类在重写父类方法时,尽量选择扩展重写,防止改变了功能。

迪米特法则

类与类交互时,在满足功能要求的基础上,传递的数据量越少越好。因为这样可能降低耦合度。

    原文作者:安财小山羊
    原文地址: https://blog.csdn.net/m0_37422217/article/details/105131004
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞