目录
5. 混入实操2:__dict__ 添加 Mixin 类中方法
将一个类的实例对象作为属性封装在另一个类中,即类和对象的组合;
当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好;
组合、继承对比如下:
圆环由两个圆组成的,圆环面积 = 外圆面积 - 内圆面积;圆环周长 = 内圆周长 + 外圆周长。
先实现圆形类,再组合两个圆形类实例作为圆环类的属性。
- #圆形类
- class Round:
- def __init__(self,radius):
- self.radius = radius
-
- def calculate_area(self):
- self.area = 3.14 * pow(self.radius,2)
- return self.area
-
- def calculate_perimeter(self):
- self.perimeter = 2 * 3.14 * self.radius
- return self.perimeter
-
- #圆环类
- class Ring:
- def __init__(self,round_out,round_in):
- self.round_out = round_out
- self.round_in = round_in
-
- def calculate_area(self):
- self.area = self.round_out.calculate_area() - self.round_in.calculate_area()
- return self.area
-
- def calculate_perimeter(self):
- self.perimeter = self.round_out.calculate_perimeter() - self.round_in.calculate_perimeter()
- return self.perimeter
-
- #生成两个圆形类的实例对象,作为圆环类实例对象的封装属性
- round1 = Round(10)
- round2 = Round(7.5)
- ring0 = Ring(round1,round2)
-
- #执行运算成功
- ring0.calculate_area()
- 137.375
- ring0.calculate_perimeter()
- 15.700000000000003
混入(Mixin 或 mix-in) 和组合一样,本身不是代码逻辑或方法,而是一种设计模式,常在面向对象编程中应用;
Mixin 的设计思想可以理解为,将程序中需要经常共享的功能细分成一个个 Mixin 类,Mixin 类通常具有如下特定:
实际编程中,通常在定义 Mixin 类时,在其名字后添加 Mixin 后缀,如:class FunctionMixin: ,但这些都不是强制要求,对于 Python 而言,也没有特殊的效果。
可以将 Mixin 类理解为功能更齐全的,更方便面向对象编程的“函数”,Python3.X 以上版本中,通常可以使用多重继承或 __dict__ 添加方法的形式,应用 Mixin 类。
Python 支持多重继承,参见类和对象2:集成,通过定义一个新的子类,多重继承多个 Mixin 类:
- #两个 Mixin 类
- class FunAMixin:
- def funa_plus(self,a,b):
- print(f'{a} + {b} = {a+b}')
-
- class FunBMixin:
- def funb_reduce(self,a,b):
- print(f'{a} - {b} = {a - b}')
-
- #创建一个多重继承多个 Mixin 类的子类
- class Calculate1(FunAMixin,FunBMixin):
- pass
-
- #调用 Mixin 类功能正常
- ctest = Calculate1()
- ctest.funa_plus(1,2)
- 1 + 2 = 3
- ctest.funb_reduce(1,2)
- 1 - 2 = -1
有时当需求发生变化需要新的功能,但直接修改类可能导致许多风险,此时我们可以创建一个类的实例对象,再通过 Mixin 类将新的方法导入到实例对象的 __dict__ 属性中,;
实例对象的 __dict__ 属性,是一个用于存储对象(可写)属性的字典,存储着类的各类方法和变量;
如下实例中,通过 Plug 父类,及其 Mixin 子类,将新的方法以“插件”的形式,“插入”或“移除”实例对象中:
- #插件父类
- class Plug:
- def __init__(self):
- self.expandfunc_list = []
-
- def plugin(self, newobject):
- for func in self.expandfunc_list:
- newobject.__dict__[func.__name__] = func
-
- def plugout(self, newobject):
- for func in self.expandfunc_list:
- del newobject.__dict__[func.__name__]
-
- #基于插件父类创建 Mixin 子类,可直接在实例对象中增删新的方法
- class FunAMixin(Plug):
- def __init__(self):
- super().__init__()
- self.expandfunc_list.append(self.funa_plus)
-
- def funa_plus(self, a, b):
- print(f'{a} + {b} = {a + b}')
-
- class FunBMixin(Plug):
- def __init__(self):
- super().__init__()
- self.expandfunc_list.append(self.funb_reduce)
-
- def funb_reduce(self, a, b):
- print(f'{a} - {b} = {a - b}')
-
- #创建测试用的类和实例对象
- class Test:
- pass
- testobject = Test()
-
- #将 Mixin 类中的方法增加到实例对象中
- FunAMixin().plugin(testobject)
- FunBMixin().plugin(testobject)
-
- #实例对象调用新增加的方法,正常执行
- testobject.funa_plus(5,1)
- 5 + 1 = 6
- testobject.funb_reduce(5,1)
- 5 - 1 = 4
-
- #将 Mixin 类中的方法从实例对象中删除
- FunBMixin().plugout(testobject)
-
- #实例对象调用已删除的方法,无法执行
- testobject.funb_reduce(5,1)
- Traceback (most recent call last):
- File "<input>", line 1, in <module>
- AttributeError: 'Test' object has no attribute 'funb_reduce'