码迷,mamicode.com
首页 > 其他好文 > 详细

组合,Mixin,类、类对象、实例对象

时间:2019-01-23 19:07:22      阅读:190      评论:0      收藏:0      [点我收藏+]

标签:改变   sel   init   分享   rtl   对象传递   self   好处   port   

  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,类、类对象、实例对象

标签:改变   sel   init   分享   rtl   对象传递   self   好处   port   

原文地址:https://www.cnblogs.com/Chris-01/p/10310739.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!