Python论坛  - 讨论区

标题:[python-chinese] 讨论一下Mixin吧!

2005年11月08日 星期二 15:50

Du Jun jdu at haiercct.com.cn
Tue Nov 8 15:50:34 HKT 2005

各位,讨论一下Mixin机制吧,一下是我向limodou提问得到的关于Mixin 的一些解释,请各位添加几个小例子来具体说明一下这个东西可好?

> Limodou,你好:
>
> 最近在看你的NewEdit源码,看到里面用到了Mixin机制,不甚明了,又到你的
> blog上找了一些资料来看,还是没有一个很清晰的概念,你这儿有这方面的资料
> 吗?能否介绍一些给我,谢谢!
>
> 恕冒昧,
>
> Arui.
>
简单讲就是在运行时改变类。在我的blog和wiki上都有相关的mixin的说明。这种
做法只有象python这样的语言才可以做得到。那么它的好象是在开发和测试阶段,
你可以不断地扩展类,但不一定要修改原来的文件,而是通过mixin机制将相关的
修改放到其它的文件中,那么这个文件其实是一个功能的扩展集,它可能包含了许
多代码的修改,但程序代码却是可以放到一起。这样的做法使得扩展和修改都比起
以前的方式要方便得多。当然也有一些不好的地方,比如启动时有些慢(因此需要
一些优化的机制)。更多的内容我不太清楚你还有什么不太明白的,希望说得具体
一些。而且mixin技术只是一个统称,并没有一个标准的实现方法,象NewEdit中就
改造了多次,而且以后很有可能还会继续改造,主要是希望减少启动时的运行消
耗。因此你可以根据mixin的思想创造适合自已使用的mixin处理方式。

我想不外乎就是使用最基本的:

基类mixin,就是改造__base__,但NewEdit没有使用
改造属性和方法,使用setattr来向一个类动态地修改

创造自已的mixin框架,以便可以支持多类,可以方便地处理mixin

有什么不明白的再讨论吧。
未经limodou同意就把这个放上来,我想limodou不会介意吧?
^_^

[导入自Mailman归档:http://www.zeuux.org/pipermail/zeuux-python]

2005年11月08日 星期二 16:15

limodou limodou at gmail.com
Tue Nov 8 16:15:02 HKT 2005

在 05-11-8,Du Jun<jdu at haiercct.com.cn> 写道:
> 各位,讨论一下Mixin机制吧,一下是我向limodou提问得到的关于Mixin 的一些解释,请各位添加几个小例子来具体说明一下这个东西可好?
>
> [snip]...
>
> 未经limodou同意就把这个放上来,我想limodou不会介意吧?

不会。

在NewEdit中Mixin是一个框架,相对复杂。在开发中面临的问题可能如下:

 * 多个类与相应的扩展对象

   因此,每个可以扩展的类需要有一个寻找的机制,因此每个可以扩展的类在NewEdit我称之为slot
class(槽类),都需要从Mixin基类派生,而且需要定义一个__mixinname__
的名字。然后需要在__init__中执行self.initmixin()

  而不同的扩展可以是常见的对象,如int, string, list, tuple, dict等,可以是方法,那么它们需要与不同的slot
class相关联,但在关联之前需要有一个采集的过程。因此每个mixin对象在定义之后需要执行Mixin中的setPlugin或setMixin,主两个方法用于区分两种不同的mixin类型,同时是进行收集的工作。而且收集工作因为是在模块的顶层代码,因此在导入前会执行。要求就是:在slot
class创建实现之间一定要完成mixin的收集工作。因此在真正的代码运行前的一些工作主要是环境的准备,包括导入所有mixin模块,执行收集的工作。

然后当类在创建实例时,由于必须调用self.initmixin(),这个方法非常重要,它装完成从收集的库中找到与类的__mixinname__对应的mixin对象,然后插入到类上,因此,NewEdit所使用的mixin是一种对类的扩展,并且在创建实例时,只完成一次的绑定工作,再创建这个类的其它实例时,这种绑定工作不会再次执行。

 * mixin的执行细节

先要执行mixin对象的收集工作,然后再调用类初始化代码.

 * mixin的存储与定义

分为Mixin和Plugin,Mixin可以为大多数的对象,如int, string, tuple, list, dict, 方法等,它的作用为:

class A:pass

Mixin之后就变成:

class A:
   a = 1
   b = {}
   def p(self, name):
      print

相当于对类进行了扩展。对于象list, tuple, dict,NewEdit的Mixin模块还会进行合并,而不是简单的替换。

而plugin全部为方法,而且在使用时应该先在程序中设置一个调用点,所有针对这个调用点的方法会形成一个执行链,这里又分为两种:一种是顺序执行,不返回结果,链中所有的方法都会执行。另一种是有返回值,如果某个方法返回成功,则后续的方法不再执行,这种返回值结构为:

flag, tuple

flag 为True 或 False。为True表示后面的方法不再执行,False表示可以继续执行。tuple为真正的返回结果,它将返回给调用者。那么调用点的代码为:

self.callplugin(args1, args2)  针对第一种无返回的调用
a = self.execplugin('init', args1, args2)
针对第二种有返回的调用,第一个参数是调用点的名字,将用于mixin对象的收集中。其它参数可以随便定义。

两种mixin对象的定义为:

Mixin.setMixin('slotname', 'attributename', object, order=Mixin.Normal)
Mixin.setPlugin('slotname', 'invokename', object, order=Mixin.Normal)

第一个参数为slot class 的mixin名
第二个参数,对于Mixin来说是绑定到槽类上的属性名,可以存在,可以不存在,对于Plugin来说是调用点的名字。order是实际的对象。order是表示在plugin链中的顺序。如果不定义就按导入时的顺序,在某些情况下你可能需要调整plugin的链结点顺序。

所有mixin对象在执行了setMixin()和setPlugin()之后会被收集到Mixin模块的全局变量中,它们按slot
class的mixin名字来分组,然后再分为Mixin和Plugin两大类,然后进行排序。这些结果在NewEdit运行时会写在debug.txt文件中。

通过这些定义规则和执行要求,就把mixin与原始的类结合在一起,最终真正在运行时生成完整的类。因此,这种类在静态方式下看上去都是代码片段落,只有在运行时才是完整的。而且NewEdit的Mixin处理并不是一成不变的,它已经变化了多次,有可能还会变化。

--
I like python!
My Blog: http://www.donews.net/limodou
NewEdit Maillist: http://groups.google.com/group/NewEdit

[导入自Mailman归档:http://www.zeuux.org/pipermail/zeuux-python]

2005年11月08日 星期二 17:20

amingsc amingsc at 163.com
Tue Nov 8 17:20:12 HKT 2005

弱弱地问一下,到底在什么时候才需要用到Mixin、plugin技术,有什么优点?

在 2005年11月8日 星期二 16:15,limodou 写道:
> 在 05-11-8,Du Jun<jdu at haiercct.com.cn> 写道:
>
> > 各位,讨论一下Mixin机制吧,一下是我向limodou提问得到的关于Mixin 的一些解释,请各位添加几个小例子来具体说明一下这个东西可好?
> >
> > [snip]...
> >
> > 未经limodou同意就把这个放上来,我想limodou不会介意吧?
>
> 不会。
>
> 在NewEdit中Mixin是一个框架,相对复杂。在开发中面临的问题可能如下:
>
>  * 多个类与相应的扩展对象
>
>    因此,每个可以扩展的类需要有一个寻找的机制,因此每个可以扩展的类在NewEdit我称之为slot
> class(槽类),都需要从Mixin基类派生,而且需要定义一个__mixinname__
> 的名字。然后需要在__init__中执行self.initmixin()
>
>   而不同的扩展可以是常见的对象,如int, string, list, tuple, dict等,可以是方法,那么它们需要与不同的slot
> class相关联,但在关联之前需要有一个采集的过程。因此每个mixin对象在定义之后需要执行Mixin中的setPlugin或setMixin,主两个
>方法用于区分两种不同的mixin类型,同时是进行收集的工作。而且收集工作因为是在模块的顶层代码,因此在导入前会执行。要求就是:在slot
> class创建实现之间一定要完成mixin的收集工作。因此在真正的代码运行前的一些工作主要是环境的准备,包括导入所有mixin模块,执行收集的工作。
>
> 然后当类在创建实例时,由于必须调用self.initmixin(),这个方法非常重要,它装完成从收集的库中找到与类的__mixinname__对应的m
>ixin对象,然后插入到类上,因此,NewEdit所使用的mixin是一种对类的扩展,并且在创建实例时,只完成一次的绑定工作,再创建这个类的其它实例时,
>这种绑定工作不会再次执行。
>
>  * mixin的执行细节
>
> 先要执行mixin对象的收集工作,然后再调用类初始化代码.
>
>  * mixin的存储与定义
>
> 分为Mixin和Plugin,Mixin可以为大多数的对象,如int, string, tuple, list, dict, 方法等,它的作用为:
>
> class A:pass
>
> Mixin之后就变成:
>
> class A:
>    a = 1
>    b = {}
>    def p(self, name):
>       print
>
> 相当于对类进行了扩展。对于象list, tuple, dict,NewEdit的Mixin模块还会进行合并,而不是简单的替换。
>
> 而plugin全部为方法,而且在使用时应该先在程序中设置一个调用点,所有针对这个调用点的方法会形成一个执行链,这里又分为两种:一种是顺序执行,不返回结
>果,链中所有的方法都会执行。另一种是有返回值,如果某个方法返回成功,则后续的方法不再执行,这种返回值结构为:
>
> flag, tuple
>
> flag 为True 或
> False。为True表示后面的方法不再执行,False表示可以继续执行。tuple为真正的返回结果,它将返回给调用者。那么调用点的代码为:
>
> self.callplugin(args1, args2)  针对第一种无返回的调用
> a = self.execplugin('init', args1, args2)
> 针对第二种有返回的调用,第一个参数是调用点的名字,将用于mixin对象的收集中。其它参数可以随便定义。
>
> 两种mixin对象的定义为:
>
> Mixin.setMixin('slotname', 'attributename', object, order=Mixin.Normal)
> Mixin.setPlugin('slotname', 'invokename', object, order=Mixin.Normal)
>
> 第一个参数为slot class 的mixin名
> 第二个参数,对于Mixin来说是绑定到槽类上的属性名,可以存在,可以不存在,对于Plugin来说是调用点的名字。order是实际的对象。order是表
>示在plugin链中的顺序。如果不定义就按导入时的顺序,在某些情况下你可能需要调整plugin的链结点顺序。
>
> 所有mixin对象在执行了setMixin()和setPlugin()之后会被收集到Mixin模块的全局变量中,它们按slot
> class的mixin名字来分组,然后再分为Mixin和Plugin两大类,然后进行排序。这些结果在NewEdit运行时会写在debug.txt文件中
>>
> 通过这些定义规则和执行要求,就把mixin与原始的类结合在一起,最终真正在运行时生成完整的类。因此,这种类在静态方式下看上去都是代码片段落,只有在运行
>时才是完整的。而且NewEdit的Mixin处理并不是一成不变的,它已经变化了多次,有可能还会变化。
>
> --
> I like python!
> My Blog: http://www.donews.net/limodou
> NewEdit Maillist: http://groups.google.com/group/NewEdit

[导入自Mailman归档:http://www.zeuux.org/pipermail/zeuux-python]

2005年11月08日 星期二 20:42

limodou limodou at gmail.com
Tue Nov 8 20:42:12 HKT 2005

在 05-11-8,amingsc<amingsc at 163.com> 写道:
> 弱弱地问一下,到底在什么时候才需要用到Mixin、plugin技术,有什么优点?
>

这种技术是自已选择的结果,也许你永远也用不上。我之所以选择这种技术来开发NewEdit,因为我知道NewEdit的开发是一个渐近的过程,那么如何在这个过程中方便地增加新的功能,方便地进行功能的隔离,而且可以选择某些功能的裁剪,基于这些想法使用Mixin是一种好的选择。而且在功能稳定之后,你完全可以将代码进行最终的合并,因为使用Mixin在运行时动态合成类在启动时会占用大量的时间。因此作为原型开发是一种好的方式。现在还没有想好,如何构造一种类似编译的技术,可以把Mixin的东西转成相对静态的东西。如果这个可以完成的话,程序编写时还是可以采用动态的Mixin方式来构造,然后通过一个生成过程合并成相对静态的代码,目的是提高运行速度,而且这一过程通过工具来保证,对于写程序没有什么影响。只不过这种想法不好实现。

因此,对于你如果不习惯或不需要这样的开发方式或功能,完全可以不用学习。Python就是这样,有些功能也许你几乎用不上,但对某些人来说可能会经常用,选择的范围很大。

--
I like python!
My Blog: http://www.donews.net/limodou
NewEdit Maillist: http://groups.google.com/group/NewEdit

[导入自Mailman归档:http://www.zeuux.org/pipermail/zeuux-python]

2005年11月08日 星期二 23:58

lof flyli3415 at gmail.com
Tue Nov 8 23:58:13 HKT 2005

终于可以发信了,
想问一下,是不是mixin的时候,当改变了一个类,然后申明了一个实例,然后又改变了这个类,那么这个时候这个实例是不是不会改变呢?
那么这个类这个时候是不是就没什么用了?

[导入自Mailman归档:http://www.zeuux.org/pipermail/zeuux-python]

2005年11月09日 星期三 08:42

limodou limodou at gmail.com
Wed Nov 9 08:42:23 HKT 2005

在 05-11-8,lof<flyli3415 at gmail.com> 写道:
> 终于可以发信了,
> 想问一下,是不是mixin的时候,当改变了一个类,然后申明了一个实例,然后又改变了这个类,那么这个时候这个实例是不是不会改变呢?
> 那么这个类这个时候是不是就没什么用了?
>

这个倒是不一定。如果你改变的是类的属性或方法,类本身的对象并不发生变化,这样实例中对于类的引用(__class__)也不会发生变化。完全可以做成类是动态改变,而不是一次改变,但那样的话调试及效率可能都是问题。不过,也许有适合的场合。

--
I like python!
My Blog: http://www.donews.net/limodou
NewEdit Maillist: http://groups.google.com/group/NewEdit

[导入自Mailman归档:http://www.zeuux.org/pipermail/zeuux-python]

如下红色区域有误,请重新填写。

    你的回复:

    请 登录 后回复。还没有在Zeuux哲思注册吗?现在 注册 !

    Zeuux © 2025

    京ICP备05028076号