当前位置 : 主页 > 编程语言 > python >

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

来源:互联网 收集:自由互联 发布时间:2022-06-15
学习笔记 开发工具:Spyder 文章目录 ​​多态​​ ​​例子(判断哪些情况是多态)​​ ​​重写​​ ​​内置可重写函数​​ ​​举个例子1(`__str__`函数)​​ ​​举个例子2(`__repr__

学习笔记
开发工具: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 = 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)--多态及设计原则_子类_02

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

举个例子

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

运算符重载

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

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

python面向对象(part4)--多态及设计原则_运算符_04

例子(对象 + #)

代码:

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)--多态及设计原则_父类_05

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

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

例子(# + 对象)

代码:

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)--多态及设计原则_运算符_07

复合运算符

python面向对象(part4)--多态及设计原则_运算符_08

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

例子(对象 += #)

代码:

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)--多态及设计原则_父类_09

比较运算符重载

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

例子

代码:

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)--多态及设计原则_父类_11

设计原则

设计原则

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

类的单一职责

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

依赖倒置

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

组合复用原则

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

里氏替换

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

迪米特法则

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

上一篇:python基础(part8)--容器类型之元组和字典
下一篇:没有了
网友评论