• Python Mixin技术介绍


    1. Mix-in技术介绍
    Mixin可以译为混入,就是在不改变原对象的情况下对其进行扩展。本文介绍了在 Python 语言中,如何实现Mixin技术,及安装的相应技巧。

    1.1. 什么是Mix-in技术
    Mix- in技术,中文不知道应该如何称呼,但意思好象是混入。它的作用是,在运行期间,动态改变类的基类或类的方法,从而使得类的表现可以发生变化。可以用在一 个通用类接口中,根据不同的选择使用不同的低层类实现,而高层类不用发生变化。而且这一实现可以在运行过程中动态进行改变。由于我也是刚看到,大家有问题 可以与我进行交流。这就是我看到的文章的链接。


    1.2. 基类的增加
    有一个类,


    class foo:
        pass
    我可以定义另外一个类,


    class foobase:
        def hello(self):
            print "hello"
    如果我直接调用:


    >>> obj=foo()
    >>> obj.hello()
    这时你会看到出错。那么我可以这样:


    >>> foo.__bases__ +=(foobase,)
    >>> obj.hello()
    hello
    成功了。原理是,每个类都有一个bases属性,它是一个tuple,用来存放所有的基类。而且在运行中,可以动态改变。所以当我们向其中增加新的基类时,再次调用原来不存在的函数,由于基类中的函数已经存在了,所以这次成功了。

    这是一个最简单的应用,可以看到我们可以动态改变类的基类。有几个注意事项要说一下:

    __bases__是一个tuple,所以增加一个值要使用tuple类型,而单个元素tuple的写法为(foobase,)

    类必须先存在。所以,如果想使用这一技术,先要将相关的类的模块导入(import)。
    由于Mix-in是一种动态技术,以多继承,对象为基础,而python正好是这样的语言,使得在python中实现这一技术非常容易。


    1.3. 函数替换
    在前面,简单地向大家介绍了一下Mix-in技术,它实现了基类的动态增加。这样我们就可以在运行时,根据选择可以动态地增加基类,从而实现不同的目的。现在还有一个问题,就是,在基类与派生类中都有同名的函数,要如何处理呢?

    在Python中,如果派生类中有与基类同名的函数,那么调用函数时,会调用派生类的函数,而不是基类的函数,可以测试一下:


    >>> class foobase:
            def a(self):
                    print "hello"

    >>> class foo(foobase):
            def a(self):
                    print "foo"

    >>> c=foo()
    >>> c.a()
    foo
    可以看出,执行的是foo类的函数。这样在使用Mix-in技术时,如果原来的类中存在与Mix类中同名的函数,那么Mix类中的函数不会运行,如果想对其进行替换怎么办呢?方法就是使用getattr()和setattr()函数。当然还是最简单的。

    定义两个类:


    >>> class foobase:
            def a(self):
                    print "hello"

    >>> class foo:
            def a(self):
                    print "foo"

    >>> f=getattr(foobase, "a")
    >>> setattr(foo, "a", f.im_func)     #f.im_func会得到真正的函数对象
    >>> c=foo()
    >>> c.a()
    hello
    可以看到,函数被替换了。

    注意,使用dir(f)还会看到其它的属性im_class,它表示这个函数属于哪个类,im_self表示属于哪个实例。


    1.4. Mix-in安装函数
    前面讲了基本的实现技术,下面给大家介绍一个Mix-in安装函数,这个函数是从前面所说的文章copy下来的。


    import types

    def MixIn(pyClass, mixInClass, makeAncestor=0):
       if makeAncestor:
         if mixInClass not in pyClass.__bases__:
            pyClass.__bases__ = (mixInClass,) + pyClass.__bases__
       else:
         # Recursively traverse the mix-in ancestor
         # classes in order to support inheritance
         baseClasses = list(mixInClass.__bases__)
         baseClasses.reverse()
         for baseClass in baseClasses:
            MixIn(pyClass, baseClass)

         # Install the mix-in methods into the class
         for name in dir(mixInClass):
            if not name.startswith('__'):
            # skip private members
               member = getattr(mixInClass, name)
               if type(member) is types.MethodType:
                   member = member.im_func
               setattr(pyClass, name, member)
    这 个函数可以将某个mix-in类安装为指定类的基类,同时可以通过关键字参数指定在基类中的顺序,是最前还是最后。因为Python在处理基类时,是安顺 序进行的,所以安装在最前则优先级最高。同时对于指定类的方法如果在mix-in类中存在,则将指定类中的方法替换成mix-in类中的方法。


       if makeAncestor:
         if mixInClass not in pyClass.__bases__:
            pyClass.__bases__ = (mixInClass,) + pyClass.__bases__
    如果makeAncestor为1,表示是安装在最前,则首先判断在pyClass的基类中是否存在mixInClass类,如果不存在,再进行安装。


       else:
         # Recursively traverse the mix-in ancestor
         # classes in order to support inheritance
         baseClasses = list(mixInClass.__bases__)
         baseClasses.reverse()
         for baseClass in baseClasses:
            MixIn(pyClass, baseClass)
    如 果makeAncestor为0,并不将mixInClass安装在最后,原作者说他在实际中没有这样用的。那么它完成什么任务呢?它实际完成了一个递 归,即从mixInClass的最底层的基类开始(因为mixInClass也可能是多重继承而来的),对pyClass中也存在的函数进行替换。这样执 行完毕后,mixInClass类中,包含所有基类中的函数,如果有与pyClass类中的函数重名的,都将pyClass中的函数替换成 mixInClass相应的函数。(有些复杂!)


         # Install the mix-in methods into the class
         for name in dir(mixInClass):
            if not name.startswith('__'):
            # skip private members
               member = getattr(mixInClass, name)
               if type(member) is types.MethodType:
                   member = member.im_func
               setattr(pyClass, name, member)
    这 步完成重名函数的替换。首先去掉私有方法(私有方法名前有'__').得到mixInClass类中的指定名字的方法对象,判断是否为方法类型。因为还有 可能取到属性。在types模块中包含了一些类型,可以用它来判断是否为方法类型。对于方法对象,如果是类方法,实际的函数应使用它的属性 im_func。然后将pyClass相应的方法替换成mixInClass中的方法。

    这样就将mixInClass安装为pyClass的基类了。

    使用例子如:


    from classa import classa
    from classb import classb
    MixIn(classa, classb) #将classb安装为classa的基类

  • 相关阅读:
    跨浏览器的事件处理程序(javascript高级程序设计第二版第十二章)
    json
    html5 本地存储Web Storage
    sicily 6497. 字符统计
    sicily 6415. linear correlation
    sicily 1154. Easy sort
    sicily 6496. 二维数组
    sicily 6423. 反向输出数字
    sicily 1636. show me the money
    sicily 1324. Score
  • 原文地址:https://www.cnblogs.com/huazi/p/2492041.html
Copyright © 2020-2023  润新知