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

网友投稿 249 2022-08-31


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

学习笔记 开发工具:Spyder

文章目录

​​多态​​

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

​​重写​​​​内置可重写函数​​

​​举个例子1(`__str__`函数)​​​​举个例子2(`__repr__`函数)​​

​​运算符重载​​

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

​​例子(对象 + #)​​

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

​​例子(# + 对象)​​

​​复合运算符​​

​​例子(对象 += #)​​

​​比较运算符重载​​

​​例子​​

​​设计原则​​

​​设计原则​​​​类的单一职责​​​​依赖倒置​​​​组合复用原则​​​​里氏替换​​​​迪米特法则​​

多态

定义

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

作用

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

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

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

类代码:

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 = ageclass 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)

举个例子2(​​__repr__​​函数)

代码:

class BunnyA: def __init__(self, name, age): self.name = name self.age = ageclass 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)

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

举个例子

运算符重载

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

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

例子(对象 + #)

代码:

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 + 5print(v02)

结果:

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

例子(# + 对象)

代码:

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 + v01print(v02)

复合运算符

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

例子(对象 += #)

代码:

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 selfv01 = Vector(10)print(id(v01))v01 += 1print(v01)print(id(v01))

比较运算符重载

例子

代码:

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 < otherv01 = Vector(10)print(v01 < 5)

结果:

设计原则

设计原则

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

类的单一职责

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

依赖倒置

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

组合复用原则

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

里氏替换

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

迪米特法则

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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:python基础(part8)--容器类型之元组和字典(简述python中列表,元组,字典的区别)
下一篇:springboot实现配置本地访问端口及路径
相关文章

 发表评论

暂时没有评论,来抢沙发吧~