组合,Mixin,类类对象实例对象
Posted chris-01
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了组合,Mixin,类类对象实例对象相关的知识,希望对你有一定的参考价值。
1、组合,将几个横向关系的组合在一起。所谓的组合就是将类的实例化放到新类里面,那么就将旧类组合进去了。
class Turtle: def __init__(self, x): # 注意 init 前面必须双下划线 self.num = x class Fish: def __init__(self, x): self.num = x class Pool: def __init__(self, x, y): self.turtle = Turtle(x) # Pool类中实例化Turtle对象 self.fish = Fish(y) def print_num(self): print(‘水池中共有乌龟 %d 只,小鱼 %d 条!‘%(self.turtle.num,self.fish.num))
调用结果:
pool = Pool(2, 7) >>> pool.print_num() 水池中共有乌龟 2 只,小鱼 7 条!
**:在新类中实例化旧类,如:self.turtle = Turtle(x) ,个人理解为将 Turtle 对象传递给 self.turtle 对象(属性),然后self.turtle 对象就具有Turtle 对象的属性了(体现在实例化 Pool 对象后,可以调用self.turtle.num,num 在 Pool 类中是没有定义的)。
2、Mixin 简介
Mixin 编程是一种开发模式,是一种将多个类中的功能单元的进行组合的利用的方式,这听起来就像是有类的继承机制就可以实现,然而这与传统的类继承有所不同。通常 Mixin 并不作为任何类的基类,也不关心与什么类一起使用,而是在运行时动态的同其他零散的类一起组合使用。
特点
使用 Mixin 机制有如下好处:
- 可以在不修改任何源代码的情况下,对已有类进行扩展;
- 可以保证组件的划分;
- 可以根据需要,使用已有的功能进行组合,来实现“新”类;
- 很好的避免了类继承的局限性,因为新的业务需要可能就需要创建新的子类。
多继承
Python支持多继承,即一个类可以继承多个子类。可以利用该特性,可以方便的实现mixin继承。如下代码,类A,B分别表示不同的功能单元,C为A,B功能的组合,这样类C就拥有了类A, B的功能。
class A: def get_a(self): print ‘a‘ class B: def get_b(self): print ‘b‘ class C(A, B): pass c = C() c.get_a() c.get_b()
__bases__
多继承的实现就会创建新类,有时,我们在运行时,希望给类A添加类B的功能时,也可以利用python的元编程特性,__bases__属性便在运行时轻松给类A添加类B的特性,如下代码:
A.__bases__ += (B,) a.get_b()
其实__bases__也是继承的机制,因为__bases__属性存储了类的基类。因此多继承的方法也可以这样实现:
class C: pass C.__bases__ += (A, B, )
插件方式
以上两种方式,都是基于多继承和python的元编程特性,然而在业务需求变化时,就需要新的功能组合,那么就需要重新修改A的基类,这回带来同步的问题,因为我们改的是类的特性,而不是对象的。因此以上修改会对所有引用该类的模块都收到影响,这是相当危险的。通常我们希望修改对象的行为,而不是修改类的。同样的我们可以利用__dict__来扩展对象的方法。
class PlugIn(object): def __init__(self): self._exported_methods = [] def plugin(self, owner): for f in self._exported_methods: owner.__dict__[f.__name__] = f def plugout(self, owner): for f in self._exported_methods: del owner.__dict__[f.__name__] class AFeature(PlugIn): def __init__(self): super(AFeature, self).__init__() self._exported_methods.append(self.get_a_value) def get_a_value(self): print ‘a feature.‘ class BFeature(PlugIn): def __init__(self): super(BFeature, self).__init__() self._exported_methods.append(self.get_b_value) def get_b_value(self): print ‘b feature.‘ class Combine:pass c = Combine() AFeature().plugin(c) BFeature().plugin(c) c.get_a_value() c.get_b_value()
3、类、类对象、实例对象
class C: count = 0 >>> a = C() >>> b = C() >>> c = C()
>>>a.count
0 >>> c.count += 10 >>> a.count 0 >>> b.count 0 >>> C.count += 100 >>> a.count 100 >>> b.count 100 >>> c.count 10
1)python中无处不对象。类中定义的属性时静态属性,类属性和类对象是绑定的,不依赖于实例对象。
2)实例化对象后,进行实例对象属性的修改不会影响类对象的属性,所以 c.count += 10不会影响 C.count 的值。
3)修改类对象属性属性之后,实例化对象的属性也会跟着改变,注意,经过实例对象修改过的属性不随着类属性的改变而改变(见上边染色部分代码),原因:个人理解为此处类似变量间的复制,实例对象是一个标签,和类对象指向同一个类属性地址,所以:a)类属性改变,实例对象属性跟着改变;b)单独修改实例对象属性是从新开辟堆栈,覆盖了该实例对象原本的类属性,所以这个修改不影响类属性,修改类属性也不影响经过修改的实例对象属性。
4、如果属性名称和方法名称一样,属性名称会覆盖方法名称。如下:给实例对象 c 定义 x 属性之后,再调用 x() 方法会报错。
以上是关于组合,Mixin,类类对象实例对象的主要内容,如果未能解决你的问题,请参考以下文章
JS面向对象——class定义类类的构造函数实例方法访问器方法静态方法继承super多态
oop思维意识,类 模块命名空间,类扩展之继承 组合mixin三种模式