Mixin 扫盲班

412 views
Skip to first unread message

lai yonghao

unread,
Jun 18, 2007, 12:03:46 AM6/18/07
to python-...@lists.python.cn, pyth...@googlegroups.com

Mixin 扫盲班
赖勇浩(http://blog.csdn.net/lanphaday)

声明:本文适合初中级Python程序员阅读,另外本文措词可能会导致阅读者不适,敬请PG。

引子
嗯,为什么要谈Mixin啊?
因为出现了Mixin这样一个东西呀,就像C++社区很多人谈论template一样啊,Python社区也很多会谈论Mixin的(以后会的,嘻嘻),所以我就来凑凑热闹了。
嗯,为什么要Mixin呀?
这个,基本上已经是我这篇文章里要讲的东西了,所以,我会用本文的大部分篇幅来回答你这个超有深度的问题。现在,就开始吧~
小时候,我家开百货店,当然,也兼营水果蔬菜啊。
小时候的事,总是特别有趣,也特别的有意义,所以今天我们就以水果店开始吧~
记得,以前很多人买水果的时候,都会问我妈一个问题,就是价格了啦~但还有两个问题也经常问到哦,就是送人应该买什么水果和什么水果可以用来送人?
嗯,年青人大多都不懂这些礼节。送水果也是很讲兆头的,比如梨和香蕉一般不用来送人,因为它们意味着离别和焦躁哦;而苹果和桔子就很受欢迎,因为它们意味着平安和吉利哦~
以此为开始
那,这跟Python有什么关系吗?
当然有啦,不然我扯那么多皮干嘛咧?现在,国产凌凌漆接到一个任务,要求他为一个水果连锁店开发一套软件;显然这个不关心国计民生这些鸡毛蒜皮的小事的武夫是搞不定这项艰巨任务的了,他就找到了你。
通过调研,客户发现两件事实:一是现在的年青人还是不懂送人应该买什么水果和什么水果可以用来送人这两个问题;二是水果连锁店的营业员100%都是年青人,他们中大部分人也不懂。
所以,客户要求在软件中必须提供一个这样的功能--可以查询一种水果是否适宜送人。
最初,你可能这样设计:
class Fruit(object):
 pass
把fruit类作为一切水果的基类,嗯,这相当明智。代码中去除了一些无需关注的代码,如价格、产地等。
现在你打算实现最受顾客欢迎的苹果:
class Apple(Fruit):
 def is_gift_fruit(self):
  return True
同样的,我又去除了一些无需关注的代码,并且打算在接下来的行文中不再提醒这一点。
Apple是一种Fruit。所以上面的实现挺符合OO的原则。
接下来让我们实现梨子吧:
class Pear(Fruit):
 def is_gift_fruit(self):
  return False
解决问题了。如果水果连锁店只卖苹果和梨子两种水果的话。
可惜,需求很多,你还要实现桔子和香蕉呢。你写下了这几行代码:
class Orange(Fruit):
 def is_gift_fruit(self):
  return True
class Banana(Fruit):
 def is_gift_fruit(self):
  return False
好臭啊,代码的坏味道!
类Apple和类Orange除了类名不同,几乎是完全重复的代码;类Pear和类Banana也是一样。
更进一层的说,这四个类都差不多啊,所以我们有必要重构一下已有代码,改善它们的设计。
改善已有代码
阅读代码,你可以发现水果只分两类:一类是可以作为礼品的,一类是不可以的。所以希望可以这样设计:
  Fruit
  / \
 GiftFruit NotGiftFruit
 / \ / \
Apple    Orange Pear Banana
嗯,加了两个中间类,看起来不错:
class GiftFruit(Fruit):
 def is_gift_fruit(self):
  return True
class NotGiftFruit(Fruit):
 def is_gift_fruit(self):
  return False
class Apple(GiftFruit):pass
class Orange(GiftFruit):pass
class Pear(NotGiftFruit):pass
class Banana(NotGiftFruit):pass
好啦,看上去很不错哦,代码精简了不少,任务完成~
新的烦恼
接下来我们来完成另一项功能:提供水果食用方法咨询。
不要笑这个需求,这是真实的市场需求。比如相当部分一辈子生活在北方的朋友就没有吃过龙眼荔枝香蕉;而南方虽然水果丰富,但不知道山竹榴莲等洋水果的也大有人在。我们这个水果连锁店业务简单,水果的食用方法也只分两种:一种是剥皮的,如桔子和香蕉;另一种是削皮的,如苹果和梨子。让我们修改原有的设计:
   Fruit
   / \
  GiftFruit NotGiftFruit
  / \ /  \
 PareG...   HuskG... PareNot... HuskNot...
 /  / /  / 
Apple     Orange  Pear  Banana
不得已,我们添加了四个类:
class PareGiftFruit(GiftFruit):
 def eat_method(self):
  return 'Pare'
class HustGiftFruit(GiftFruit):
 def eat_method(self):
  return 'Husk'
class PareNotGiftFruit(NotGiftFruit):
 def eat_method(self):
  return 'Pare'
class HuskNotGiftFruit(NotGiftFruit):
 def eat_method(self):
  return 'Husk'
怎么这四个类这么像啊?汗。。。。
先忍忍,把AOPB四种水果的实现改改:
class Apple(PareGiftFruit):pass
class Orange(HuskGiftFruit):pass
class Pear(PareNotGiftFruit):Pass
class Banana(HuskNotGiftFruit):pass
我已经忍无可忍了。这个设计不仅仅又引入了好不容易消除的重复代码,而且还修改了AOPB这四个类的实现。这种设计的扩展性也不好,如果以后要提供水果的其它特点,比如是进口水果还是国产水果。天啊,这还了得!加上这个特性,我要实现NativePareGiftFruit、NativeHuskGiftFruit等类共8个(2的三次方)啊。水果的特征多得很,随便算算可能超过16种啊,65536个类?叫我去死吧~单是长达16个单词的类名我就崩溃了!
现在,你们都应该意识到这种实现方法实在是一种龌龊的设计了。那,我们应该怎么样设计呢?
Pythonic的方案
该是Mixin出场的时候了!
先来看看Mixin的实现吧:
class Fruit(object):
 pass
class GiftMixin(object):
 def is_gift_fruit(self):
  return True
class NotGiftMixin(object):
 def is_gift_fruit(self):
  return False
class PareMixin(object):
 def eat_method(self):
  return 'Pare'
class HuskMixin(object):
 def eat_method(self):
  return 'Husk'
class Apple(GiftMixin, PareMixin, Fruit):pass
class Orange(GiftMixin, HuskMixin, Fruit):pass
class Pear(NotGiftMixin, PareMixin, Fruit):pass
class Banana(NotGiftMixin, HuskMixin, Fruit):pass
编码完成!这就是Mixin,就是这么简单,以致我无法再说出任何言语,因为我觉得上面的代码已经完整地表达了我想要表达的思想。
注意, 因为 Python 里面多重继承时如果被调用的成员函数只存在于父类中,则按类声明的父类从左到右查找调用的, 所以主类被放在右边, MixIn 被放在左边,才能正确地调用到Mixin的成员函数。
Mixin的好处是可以为主类(如Fruit)添加任意多的Mixin来实现多态,比如刚才说的水果有进口和国产两个特征,现在相当容易实现:
class NativeMixin(object):
 def Locality(self):
  return 'Native'
class ForeignMixin(object):
 def Locality(self):
  return 'Foreign'
class Apple(ForeignMixin, GiftMixin, PareMixin, Fruit):pass #进口红富士
class Orange(NativeMixin, GiftMixin, HuskMixin, Fruit):pass
class Pear(NativeMixin, NotGiftMixin, PareMixin, Fruit):pass
class Banana(NativeMixin, NotGiftMixin, HuskMixin, Fruit):pass
简单多了,只加了两个类,对AOPB的实现也只是增加了一个基类(增加总是胜过修改)。
利用Mixin我们还可以增加无数总特征,而无需对已有代码作太大改动。
另外,我们还获得了可重用性。比如NativeMixin和ForeignMixin跟主类Human结合,可以做出国人和老外两个类哦~也许水果连锁店软件以后会考虑记录关于客户是否外国人的信息呢。
除此之外
这时候,你可能会说:水果连锁店软件只是你杜撰的一个项目,Mixin有什么实际用处吗?当然有啦!其实Mixin并不是什么高阶的Python技巧,早有就很多开源项目使用这个技巧了,典型的,比如Python项目啊! 在Python自带的SocketServer.py里就应用了Mixin来实现基于进程和基于线程的两种TCP/UDP服务模型,在Tkinter和Python的其它模块也可以见到它的踪迹,如果你留意的话。
# SocketServer.py 里的Mixin
class ForkingUDPServer(ForkingMixIn, UDPServer): pass
class ForkingTCPServer(ForkingMixIn, TCPServer): pass
class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
确切来说,我对Mixin来实现的水果连锁店的实现仍然相当不满意,但如果我们想要足够面向对象,也就基本上只能接受如此解决方案了。如果有一天你不能忍受每增加一种特征你就必须编写N(N>=2)个Mixin,然后都必须给已经存在的AOPB代码增加一个基类(想想,水果店卖的可不止四种水果,你会更头大),那,就考虑把OO抛弃吧!
鸣谢
在本文成文过程中,沈崴(http://eishn.blog.163.com)给我很大帮助,特此鸣谢。

黄毅

unread,
Jun 18, 2007, 12:29:12 AM6/18/07
to pyth...@googlegroups.com
class Fruit(object):
    is_gift_fruit = False
    eat_method = ''
    def is_gift_fruit(self):
        return self.is_gift_fruit
    def eat_method(self):
        return self.eat_method
class Apple(Fruit):
    is_gift_fruit = True
    eat_method = 'Pare'

Zoom.Quiet

unread,
Jun 18, 2007, 12:31:00 AM6/18/07
to pyth...@googlegroups.com
On 6/18/07, lai yonghao <lanp...@gmail.com> wrote:
>
so great! 这种科普文章多多多多益善哪!
收录在啄木鸟维基,欢迎持续维护!
http://wiki.woodpecker.org.cn/moin/FlyintoMixin

咔咔咔,感觉N有俺的文风哪!可以收录在"可愛的Python"-- 作弊条部分?
http://wiki.woodpecker.org.cn/moin/ObpLovelyPython


--
'''Time is unimportant, only life important!
http://zoomquiet.org
blog@http://blog.zoomquiet.org/pyblosxom/
wiki@http://wiki.woodpecker.org.cn/moin/ZoomQuiet
scrap@http://floss.zoomquiet.org
douban@http://www.douban.com/people/zoomq/
____________________________________
Pls. use OpenOffice.org to replace M$ Office.
http://zh.openoffice.org
Pls. use 7-zip to replace WinRAR/WinZip.
http://7-zip.org/zh-cn/
You can get the truely Freedom 4 software.
'''

Can Xue

unread,
Jun 18, 2007, 12:32:51 AM6/18/07
to pyth...@googlegroups.com
原创吗?写得不错,这种风格很独特,但是容易理解。

在 07-6-18,lai yonghao<lanp...@gmail.com> 写道:

黄毅

unread,
Jun 18, 2007, 12:36:39 AM6/18/07
to pyth...@googlegroups.com
class Giftable(object):
    is_gift = True
    def is_gift(self):
          return self.is_gift
 
class UnGiftable(Giftable):
    is_gift = False
 
class Eatable(object):
     eat_method = ''
     def eat_method(self):
          return self.eat_method
 
class Fruit(object):
     pass
class Apple(Fruit, Giftable, Eatable):
     eat_method = 'Bare'
 
class Banana(Fruit, UnGiftable, Eatable):
     eat_method = 'Hust'
--
http://codeplayer.blogspot.com/

黄毅

unread,
Jun 18, 2007, 12:37:21 AM6/18/07
to pyth...@googlegroups.com
就是多重继承嘛,mixin 这个词相对奇怪许多。
--
http://codeplayer.blogspot.com/

Zoom.Quiet

unread,
Jun 18, 2007, 12:48:39 AM6/18/07
to pyth...@googlegroups.com
On 6/18/07, 黄毅 <yi.cod...@gmail.com> wrote:
> 就是多重继承嘛,mixin 这个词相对奇怪许多。
>
是也乎,所以,应该继续写下去,
UliPad 的应用经验,主要是Mixin 的动态嵌入类树,而不是创建时的多重继承声明;)

这里,可以利用面向数据的概念,将食用方法,作为一个对象字典统一维护,
水果也同样,
文本实际处理体就可以非常精简,
再也不用针对新水果写新类了,而且在字典中追加条目就好 ;)

lanp...@gmail.com

unread,
Jun 18, 2007, 12:52:32 AM6/18/07
to python.cn
呵呵,写这篇文章也是想让更多人看到哈。
所以,这些就悉听尊便吧。

On 6月18日, 下午12时31分, Zoom.Quiet <zoom.qu...@gmail.com> wrote:


> On 6/18/07, lai yonghao <lanpha...@gmail.com> wrote:
>
> so great! 这种科普文章多多多多益善哪!
> 收录在啄木鸟维基,欢迎持续维护!http://wiki.woodpecker.org.cn/moin/FlyintoMixin
>
> 咔咔咔,感觉N有俺的文风哪!可以收录在"可愛的Python"-- 作弊条部分?http://wiki.woodpecker.org.cn/moin/ObpLovelyPython
>
>
>
>
>
>
>
> > Mixin 扫盲班
> > 赖勇浩(http://blog.csdn.net/lanphaday)
>
> > 声明:本文适合初中级Python程序员阅读,另外本文措词可能会导致阅读者不适,敬请PG。
>
> > 引子
> > 嗯,为什么要谈Mixin啊?
> > 因为出现了Mixin这样一个东西呀,就像C++社区很多人谈论template一样啊,Python社区也很多会谈论Mixin的(以后会的,嘻嘻),所以我 就来凑凑热闹了。
> > 嗯,为什么要Mixin呀?
> > 这个,基本上已经是我这篇文章里要讲的东西了,所以,我会用本文的大部分篇幅来回答你这个超有深度的问题。现在,就开始吧~
> > 小时候,我家开百货店,当然,也兼营水果蔬菜啊。
> > 小时候的事,总是特别有趣,也特别的有意义,所以今天我们就以水果店开始吧~
> > 记得,以前很多人买水果的时候,都会问我妈一个问题,就是价格了啦~但还有两个问题也经常问到哦,就是送人应该买什么水果和什么水果可以用来送人?
> > 嗯,年青人大多都不懂这些礼节。送水果也是很讲兆头的,比如梨和香蕉一般不用来送人,因为它们意味着离别和焦躁哦;而苹果和桔子就很受欢迎,因为它们意味着平安 和吉利哦~
> > 以此为开始
> > 那,这跟Python有什么关系吗?

> > 当然有啦,不然我扯那么多皮干嘛咧?现在,国产凌凌漆接到一个任务,要求他为一个水果连锁店开发一套软件;显然这个不关心国计民生这些鸡毛蒜皮的小事的武夫是搞 不定这项艰巨任务的了,他就找到了你。

> > 我已经忍无可忍了。这个设计不仅仅又引入了好不容易消除的重复代码,而且还修改了AOPB这四个类的实现。这种设计的扩展性也不好,如果以后要提供水果的其它特 点,比如是进口水果还是国产水果。天啊,这还了得!加上这个特性,我要实现NativePareGiftFruit、NativeHuskGiftFruit等 类共8个(2的三次方)啊。水果的特征多得很,随便算算可能超过16种啊,65536个类?叫我去死吧~单是长达16个单词的类名我就崩溃了!

> > 在Python自带的SocketServer.py里就应用了Mixin来实现基于进程和基于线程的两种TCP/UDP服务模型,在Tkinter和Pyth on的其它模块也可以见到它的踪迹,如果你留意的话。


> > # SocketServer.py 里的Mixin
> > class ForkingUDPServer(ForkingMixIn, UDPServer): pass
> > class ForkingTCPServer(ForkingMixIn, TCPServer): pass
> > class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
> > class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass

> > 确切来说,我对Mixin来实现的水果连锁店的实现仍然相当不满意,但如果我们想要足够面向对象,也就基本上只能接受如此解决方案了。如果有一天你不能忍受每增 加一种特征你就必须编写N(N>=2)个Mixin,然后都必须给已经存在的AOPB代码增加一个基类(想想,水果店卖的可不止四种水果,你会更头大),那,就 考虑把OO抛弃吧!


> > 鸣谢
> > 在本文成文过程中,沈崴(http://eishn.blog.163.com)给我很大帮助,特此鸣谢。
>
> --

> '''Time is unimportant, only life important!http://zoomquiet.org


> blog@http://blog.zoomquiet.org/pyblosxom/
> wiki@http://wiki.woodpecker.org.cn/moin/ZoomQuiet
> scrap@http://floss.zoomquiet.org
> douban@http://www.douban.com/people/zoomq/
> ____________________________________
> Pls. use OpenOffice.org to replace M$ Office.
> http://zh.openoffice.org
> Pls. use 7-zip to replace WinRAR/WinZip.
> http://7-zip.org/zh-cn/

> You can get the truely Freedom 4- 隐藏被引用文字 -
>
> - 显示引用的文字 -...
>
> 阅读更多

沈崴

unread,
Jun 18, 2007, 1:31:36 AM6/18/07
to python.cn
勇浩兄之前和我聊过, 他感兴趣的 MixIn 好像是下面这个样子的。
大概是面向 "扫盲" 的原因, 他就稍稍写得浅显了, 推荐勇浩兄再出一些续作 :)

#!/usr/bin/env python
# 仿黄毅大师的版本

class Instance:
def __init__(self, *args, **kw):
self.__dict__.update(kw)
for m in args:
m(self)

def config(self, *args, **kw):
self.__dict__.update(kw)
for m in args:
m(self)

return self

def i_am_gift(self):
# self.is_gift = True # Why not :)

self.is_gift = lambda: True

def i_am_not_gift(self):
self.is_gift = lambda: False

def eatable(eat_method = ''):
def config_eat_method(self):
self.eat_method = lambda: eat_method

return config_eat_method

def Apple():
return Instance(i_am_gift, eatable('Bare'))

def Banana():
return Instance(i_am_not_gift, eatable('Hust'))

if __name__ == '__main__':
apple = Apple()
print apple.is_gift()

apple.config(i_am_not_gift)
print apple.is_gift()

banana = Banana()
print apple.eat_method()
print banana.eat_method()

On 6月18日, 下午12时36分, "黄毅" <yi.codepla...@gmail.com> wrote:
> class Giftable(object):
> is_gift = True
> def is_gift(self):
> return self.is_gift
>
> class UnGiftable(Giftable):
> is_gift = False
>
> class Eatable(object):
> eat_method = ''
> def eat_method(self):
> return self.eat_method
>
> class Fruit(object):
> pass
> class Apple(Fruit, Giftable, Eatable):
> eat_method = 'Bare'
>
> class Banana(Fruit, UnGiftable, Eatable):
> eat_method = 'Hust'
>

> On 6/18/07, 黄毅 <yi.codepla...@gmail.com> wrote:
>
>
>
> > class Fruit(object):
> > is_gift_fruit = False
> > eat_method = ''
> > def is_gift_fruit(self):
> > return self.is_gift_fruit
> > def eat_method(self):
> > return self.eat_method
> > class Apple(Fruit):
> > is_gift_fruit = True
> > eat_method = 'Pare'
>
> > --
> >http://codeplayer.blogspot.com/
>
> --http://codeplayer.blogspot.com/

---
沈崴 (努力学习 Python 中 ...)
http://blog.163.com/eishn

依山居

unread,
Jun 18, 2007, 9:32:52 AM6/18/07
to pyth...@googlegroups.com
呵呵,下次会课的时候谁给我们上一下mixin的课吧
 

依山居
2007-06-18

发件人: Zoom.Quiet
发送时间: 2007-06-18 12:31:23
抄送:
主题: [CPyUG:27973]_Re:_Mixin_扫盲班

头太晕

unread,
Jun 18, 2007, 9:53:04 AM6/18/07
to python-...@lists.python.cn


在07-6-18,马宏亮 <mhl...@gmail.com> 写道:
Python里没有接口吗?

这比接口灵活多了。。。

顶楼主。。。。 顶楼主的肾。。。。岗岗的顶。。。。


头太晕

unread,
Jun 18, 2007, 10:21:26 AM6/18/07
to python-...@lists.python.cn


在07-6-18,马宏亮 <mhl...@gmail.com> 写道:
为什么灵活多了?这不跟接口一样的目的吗?

目的一样,做的工作少了。


boost...@googlemail.com

unread,
Jun 18, 2007, 12:12:53 PM6/18/07
to python.cn
> Python里没有接口吗?
PEP 245 : Python Interface Syntax 没有被接受!
此外, mixin和factory不是太一样。AJAX包PROTOTPYE里也用MIXIN这术语了。
好像INTERFACE, 比如JAVA每个类还是要自己实现的吧,MIXIN就实现一次, 当然, 也可以覆盖哪另当别论。

好像UliPad的老板还没讲话呀。


limodou

unread,
Jun 18, 2007, 8:40:29 PM6/18/07
to pyth...@googlegroups.com

此Mixin与UliPad的中Mixin不是一种实现。楼主所讲Mixin是多重继承来实现的。而UliPad中的Mixin并不是通过多重继承,而是动态在运行时修改,增加对原类的一些属性,方法,从而实现对类的扩展。这完全是一种动态行为,而不是在编程时就已经看到最终的结果。而且UliPad中有如何定义Mixin部件,如何搜集部件,如何组装的一系列处理。有兴趣可以看UliPad自带的文档其中有关于使用Mixin技术的说明,可以看出与楼主的不一样。

--
I like python!
UliPad <<The Python Editor>>: http://wiki.woodpecker.org.cn/moin/UliPad
My Blog: http://www.donews.net/limodou

kernel1983

unread,
Jun 18, 2007, 9:02:45 PM6/18/07
to python.cn
我喜欢最后一句话

那,就 考虑把OO抛弃吧!


水果就是水果,如果水果的标签上标着苹果,那就是苹果,何必一定要搞个类出来呢?


既然是动态语言,普及以下DuckType吧!

On Jun 19, 8:40 am, limodou <limo...@gmail.com> wrote:


> On 6/19/07, boostpy2...@yahoo.com.cn <boostpy2...@googlemail.com> wrote:
>
> > > Python里没有接口吗?
> > PEP 245 : Python Interface Syntax 没有被接受!
> > 此外, mixin和factory不是太一样。AJAX包PROTOTPYE里也用MIXIN这术语了。
> > 好像INTERFACE, 比如JAVA每个类还是要自己实现的吧,MIXIN就实现一次, 当然, 也可以覆盖哪另当别论。
>
> > 好像UliPad的老板还没讲话呀。
>

> 此Mixin与UliPad的中Mixin不是一种实现。楼主所讲Mixin是多重继承来实现的。而UliPad中的Mixin并不是通过多重继承,而是动态在 运行时修改,增加对原类的一些属性,方法,从而实现对类的扩展。这完全是一种动态行为,而不是在编程时就已经看到最终的结果。而且UliPad中有如何定义Mi xin部件,如何搜集部件,如何组装的一系列处理。有兴趣可以看UliPad自带的文档其中有关于使用Mixin技术的说明,可以看出与楼主的不一样。

limodou

unread,
Jun 18, 2007, 9:05:25 PM6/18/07
to pyth...@googlegroups.com
On 6/19/07, kernel1983 <kerne...@gmail.com> wrote:
> 我喜欢最后一句话
>
> 那,就 考虑把OO抛弃吧!
>
>
> 水果就是水果,如果水果的标签上标着苹果,那就是苹果,何必一定要搞个类出来呢?
>
>
> 既然是动态语言,普及以下DuckType吧!
>

Mixin如果没有类根本没什么用处。难道就这么恐惧OO吗?

limodou

unread,
Jun 18, 2007, 9:06:25 PM6/18/07
to pyth...@googlegroups.com
On 6/19/07, limodou <lim...@gmail.com> wrote:
> On 6/19/07, kernel1983 <kerne...@gmail.com> wrote:
> > 我喜欢最后一句话
> >
> > 那,就 考虑把OO抛弃吧!
> >
> >
> > 水果就是水果,如果水果的标签上标着苹果,那就是苹果,何必一定要搞个类出来呢?
> >
> >
> > 既然是动态语言,普及以下DuckType吧!
> >
>
> Mixin如果没有类根本没什么用处。难道就这么恐惧OO吗?
>
应该不是没有什么用处,而是根本就不会有Mixin这种东西了。Mixin就是建立在类之上的东西,没有基础的类,何谈Mixin?

lanp...@gmail.com

unread,
Jun 18, 2007, 10:50:17 PM6/18/07
to python.cn
感谢大家关注,嗯,就像沈崴大师说的,这只是面向扫盲班的版本,只讲了一些初阶知识,希望达到一个普及的作用罢了~

python相当动态,可以写出匪夷所思的代码,之所以只谈了区区之Mixin,一则篇幅,二则讲一个循序渐进,以后我会努力多作一些介绍,敬请持续关
注。

赖勇浩

On 6月19日, 上午8时40分, limodou <limo...@gmail.com> wrote:


> On 6/19/07, boostpy2...@yahoo.com.cn <boostpy2...@googlemail.com> wrote:
>
> > > Python里没有接口吗?
> > PEP 245 : Python Interface Syntax 没有被接受!
> > 此外, mixin和factory不是太一样。AJAX包PROTOTPYE里也用MIXIN这术语了。
> > 好像INTERFACE, 比如JAVA每个类还是要自己实现的吧,MIXIN就实现一次, 当然, 也可以覆盖哪另当别论。
>
> > 好像UliPad的老板还没讲话呀。
>

> 此Mixin与UliPad的中Mixin不是一种实现。楼主所讲Mixin是多重继承来实现的。而UliPad中的Mixin并不是通过多重继承,而是动态在 运行时修改,增加对原类的一些属性,方法,从而实现对类的扩展。这完全是一种动态行为,而不是在编程时就已经看到最终的结果。而且UliPad中有如何定义Mi xin部件,如何搜集部件,如何组装的一系列处理。有兴趣可以看UliPad自带的文档其中有关于使用Mixin技术的说明,可以看出与楼主的不一样。

大郎

unread,
Jun 19, 2007, 2:03:25 AM6/19/07
to python-...@lists.python.cn
我只能说这是我读到最好的说教式的Python文章。
远比那些赶干巴巴的例子生动得多,其实这里说明了两点:

1, 是开发思想和开发方法
2, python本身教程

只是看到二楼上的回复,让人有些寒心。

On 6/19/07, 东子/hydon < hydo...@gmail.com> wrote:
接口不提供实现, Mixin提供了实现(默认的实现? 可以重写吗?)

在07-6-18,头太晕 <tor...@gmail.com> 写道:


在07-6-18,马宏亮 <mhl...@gmail.com > 写道:
为什么灵活多了?这不跟接口一样的目的吗?

目的一样,做的工作少了。



_______________________________________________
python-chinese
Post: send python-...@lists.python.cn
Subscribe: send subscribe to python-chin...@lists.python.cn
Unsubscribe: send unsubscribe to   python-chin...@lists.python.cn
Detail Info: http://python.cn/mailman/listinfo/python-chinese



--

努力做好每一件事
TRY TO DO MY BEST

_______________________________________________
python-chinese
Post: send python-...@lists.python.cn
Subscribe: send subscribe to python-chin...@lists.python.cn
Unsubscribe: send unsubscribe to   python-chin...@lists.python.cn
Detail Info: http://python.cn/mailman/listinfo/python-chinese



--
我走到一个陌生的地方, 告诉别人 我要去流浪
哦,我要去疗伤……

Gtalk: iexper(at)gmail.com
域名过期了

HoLin

unread,
Jun 19, 2007, 5:29:00 AM6/19/07
to python-...@lists.python.cn
很不错,喜欢这样的方式。
原本理解的MixIn是可以include进来的方法,在当前文件里面可以直接调用。Python没怎么用过。= =!

在07-6-19,大郎 <iex...@gmail.com> 写道:



--
Regards
HoLin

3751

unread,
Jun 19, 2007, 5:45:32 AM6/19/07
to python-...@lists.python.cn
在07-6-19,大郎 <iex...@gmail.com> 写道:
只是看到二楼上的回复,让人有些寒心。
我倒是觉得哭笑不得。

antiacui

unread,
Jun 19, 2007, 5:47:19 AM6/19/07
to python.cn
呃,python不是太熟,不过从用c++的经验来看,楼主这个例子很糟糕啊,如果按c++的设计来说,is_gift_fruit和
eat_method明显是类的static函数,这种情况下一般是采用泛型而不是多重继承+多态,写起来和沈崴的那个有点类似:
typedef template<(i_am_gift, boost::bind(eatable, "Pare")>Fruit Apple;
如果要是想举多重继承的例子,尽量还是找那种需要self的例子
不过貌似python的两种方法效率是一样的,这个不像c++,那里面用泛型可以提高执行效率(代价是代码增长&编译变慢)

On 6月18日, 下午12时03分, "lai yonghao" <lanpha...@gmail.com> wrote:
> Mixin 扫盲班
> 赖勇浩(http://blog.csdn.net/lanphaday)
>
> 声明:本文适合初中级Python程序员阅读,另外本文措词可能会导致阅读者不适,敬请PG。
>
> *引子*

> 嗯,为什么要谈Mixin啊?
> 因为出现了Mixin这样一个东西呀,就像C++社区很多人谈论template一样啊,Python社区也很多会谈论Mixin的(以后会的,嘻嘻),所以我就来凑凑热闹了。
> 嗯,为什么要Mixin呀?
> 这个,基本上已经是我这篇文章里要讲的东西了,所以,我会用本文的大部分篇幅来回答你这个超有深度的问题。现在,就开始吧~
> 小时候,我家开百货店,当然,也兼营水果蔬菜啊。
> 小时候的事,总是特别有趣,也特别的有意义,所以今天我们就以水果店开始吧~
> 记得,以前很多人买水果的时候,都会问我妈一个问题,就是价格了啦~但还有两个问题也经常问到哦,就是送人应该买什么水果和什么水果可以用来送人?
> 嗯,年青人大多都不懂这些礼节。送水果也是很讲兆头的,比如梨和香蕉一般不用来送人,因为它们意味着离别和焦躁哦;而苹果和桔子就很受欢迎,因为它们意味着平安和吉利哦~
> *以此为开始*
> *新的烦恼*
> *Pythonic的方案*
> *除此之外*

> 这时候,你可能会说:水果连锁店软件只是你杜撰的一个项目,Mixin有什么实际用处吗?当然有啦!其实Mixin并不是什么高阶的Python技巧,早有就很多开源项目使用这个技巧了,典型的,比如Python项目啊!
> 在Python自带的SocketServer.py里就应用了Mixin来实现基于进程和基于线程的两种TCP
> /UDP服务模型,在Tkinter和Python的其它模块也可以见到它的踪迹,如果你留意的话。
> # SocketServer.py 里的Mixin
> class ForkingUDPServer(ForkingMixIn, UDPServer): pass
> class ForkingTCPServer(ForkingMixIn, TCPServer): pass
> class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
> class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
> 确切来说,我对Mixin来实现的水果连锁店的实现仍然相当不满意,但如果我们想要足够面向对象,也就基本上只能接受如此解决方案了。如果有一天你不能忍受每增加一种特征你就必须编写N(N>=2)个Mixin,然后都必须给已经存在的AOPB代码增加一个基类(想想,水果店卖的可不止四种水果,你会更头大),那,就考虑把OO抛弃吧!
> *鸣谢*
> 在本文成文过程中,沈崴(http://eishn.blog.163.com)给我很大帮助,特此鸣谢。

王超凡

unread,
Jun 19, 2007, 7:58:44 AM6/19/07
to python-...@lists.python.cn
真有扫盲的效果

在07-6-19,3751 <lwm...@gmail.com> 写道:
在07-6-19,大郎 < iex...@gmail.com> 写道:
只是看到二楼上的回复,让人有些寒心。
我倒是觉得哭笑不得。

张沈鹏(电子科大 08年毕业)

unread,
Jun 19, 2007, 9:23:35 AM6/19/07
to pyth...@googlegroups.com
> 既然是动态语言,普及以下DuckType吧!
DuckType怎么我总觉得像C++里面的泛型编程呢?
有什么区别吗?

在 07-6-19,kernel1983<kerne...@gmail.com> 写道:


--
欢迎访问我的博客:
http://zsp.javaeye.com/

--张沈鹏

antiacui

unread,
Jun 19, 2007, 1:07:37 PM6/19/07
to python.cn
呃,那个叫duck typing
这个东东和c++的泛型是有本质区别的,python的对象里面除了几个基本方法(__init__,__del__,__str__,等等)和几个基
本属性(__dict__,__class__,__module__,等等)之外,都是扔在对象本身的__dict__,或者对象的type的
__dict__,或者对象的类(注意,一个类的实例的type是types.InstanceType,而不是这个类)的__dict__里面(当
然,如果是使用__slots__定义的new-style类,那么是放在预先分配好的空间里),也就是说其实python中的每个类的实例差不多都是
相同的结构,一个dict和一大堆基础的属性;而c++的一个类的参数和方法的存储结构都是在编译期间确定的,两个不同类的实例的结构区别很大。这样在
python的duck typing中,都在是运行时通过__dict__或者__slots__之类的东东来确定实际要调用的方法,实际的调用代码
只有一份;而在c++的泛型中,会在编译期间根据遇到的参数的不同类型生成相应的调用代码,也就是说编译器碰到多少种类型就要生成多少份调用代码,实际
执行中也是根据不同的类型直接调用相应的函数,这样的好处是可以提高运行时的效率,并且减少出错的可能(因为如果有类型没实现相应的函数,那么编译期间
就会直接出错),但是坏处就是不能动态创建类型,而且增加编译时间。
乱糟糟的说了一大堆,简单来说,主要区别就是python的这个是动态的,c++的那个是静态的:)

On 6月19日, 下午9时23分, "张沈鹏(电子科大 08年毕业)" <zsp...@gmail.com> wrote:
> > 既然是动态语言,普及以下DuckType吧!
>
> DuckType怎么我总觉得像C++里面的泛型编程呢?
> 有什么区别吗?
>

> 在 07-6-19,kernel1983<kernel1...@gmail.com> 写道:

antiacui

unread,
Jun 19, 2007, 1:08:18 PM6/19/07
to python.cn
呃,那个叫duck typing
这个东东和c++的泛型是有本质区别的,python的对象里面除了几个基本方法(__init__,__del__,__str__,等等)和几个基
本属性(__dict__,__class__,__module__,等等)之外,都是扔在对象本身的__dict__,或者对象的type的
__dict__,或者对象的类(注意,一个类的实例的type是types.InstanceType,而不是这个类)的__dict__里面(当
然,如果是使用__slots__定义的new-style类,那么是放在预先分配好的空间里),也就是说其实python中的每个类的实例差不多都是
相同的结构,一个dict和一大堆基础的属性;而c++的一个类的参数和方法的存储结构都是在编译期间确定的,两个不同类的实例的结构区别很大。这样在
python的duck typing中,都在是运行时通过__dict__或者__slots__之类的东东来确定实际要调用的方法,实际的调用代码
只有一份;而在c++的泛型中,会在编译期间根据遇到的参数的不同类型生成相应的调用代码,也就是说编译器碰到多少种类型就要生成多少份调用代码,实际
执行中也是根据不同的类型直接调用相应的函数,这样的好处是可以提高运行时的效率,并且减少出错的可能(因为如果有类型没实现相应的函数,那么编译期间
就会直接出错),但是坏处就是不能动态创建类型,而且增加编译时间。
乱糟糟的说了一大堆,简单来说,主要区别就是python的这个是动态的,c++的那个是静态的:)

On 6月19日, 下午9时23分, "张沈鹏(电子科大 08年毕业)" <zsp...@gmail.com> wrote:

> > 既然是动态语言,普及以下DuckType吧!
>
> DuckType怎么我总觉得像C++里面的泛型编程呢?
> 有什么区别吗?
>
> 在 07-6-19,kernel1983<kernel1...@gmail.com> 写道:

Liming_Do

unread,
Jun 19, 2007, 9:55:23 PM6/19/07
to pyth...@googlegroups.com, python-...@lists.python.cn
非常佩服楼主无私贡献的文章,知识丰富活泼形象,受益非浅!
MixIn是在运行期将方法动态赋予已经实例化的成员
但是兄弟弱弱的认为这个例子是多重继承,不能称作MixIn
而您的代码在实例化的时候已经确定了(闪一个先,免得被扁@_@)
不使用多重继承的话,这是我觉得好玩儿的写法:
 
#!/usr/bin/env python
#
# Copyright(c) 2007 Leon Dong
# E-mail : Leon...@gmail.com
#
 
class Fruit(type):
   
    def __new__(cls, name, bases, methods):
        return type.__new__(cls,name,bases,methods)
   
    def __init__(cls, name, bases, methods):
        super(Fruit,cls).__init__(name, bases, methods)
 
Apple = Fruit('Apple',(),{'isGift':lambda self: True, 'eatMethod':lambda self: 'Pare'})
Orange = Fruit('Orange',(),{'isGift':lambda self: True, 'eatMethod':lambda self: 'Husk'})
Pear = Fruit('Pear',(),{'isGift':lambda self: False, 'eatMethod':lambda self: 'Pare'})
Banana = Fruit('Banana',(),{'isGift':lambda self: False, 'eatMethod':lambda self: 'Husk'})
   
if __name__=='__main__':
      
    print map(lambda f: (f.isGift(),f.eatMethod()),[Apple(),Orange(),Pear(),Banana()])
 
> C:\Python25\python.exe -u "D:\LeonDong\StudyStudio\Python\MixIn\meta.py"
[(True, 'Pare'), (True, 'Husk'), (False, 'Pare'), (False, 'Husk')]
 
 
对于MixIn机制的实现比较而言我更认可默兜兄UliPad中的做法
我的理解是PlugIn是指在实例化时动态增加方法和属性
比如eclipse的plugin只要丢到指定的folder下重启动之后就可以被加载
MixIn指实例化以后再动态的增加对新的方法和属性的调用入口
这是我的理解的MixIn机制的示例,欢迎拍砖:
 
#!/usr/bin/env python
#
# Copyright(c) 2007 Leon Dong
# E-mail : Leon...@gmail.com
#
 
__mixinset__ = {}
 
class Fruit(object):
   
    __mixinname__ = ''
   
    def __init__(self):
        if __mixinset__.has_key(self.__mixinname__):
            plugins,mixins = __mixinset__[self.__mixinname__]
            setattr(self.__class__,'__plugins__',plugins)
            setattr(self.__class__,'__mixins__',mixins)
        self.initMixIn()
        self.execPlugIn()
   
    def initMixIn(self):
        for key,value in self.__mixins__.items():
            setattr(self.__class__,key,value)
   
    def execPlugIn(self):
        for key,value in self.__plugins__.items():
            setattr(self.__class__,key,value)
            try:
                getattr(self,key)()
            except SystemExit:
                raise
           
    def execMixIn(self, name, *args, **kwargs):
        try:
            f = getattr(self,name)
            f(args[0])
        except SystemExit:
            raise
       
class Apple(Fruit):
    __mixinname__ = 'Apple'
   
class Orange(Fruit):
    __mixinname__ = 'Orange'
 
class Pear(Fruit):
    __mixinname__ = 'Pear'
   
class Banana(Fruit):
    __mixinname__ = 'Banana'
   
def isGift(self):
    self.isGift = True
    print self.isGift
 
def notGift(self):
    self.isGift = False
    print self.isGift
   
def eatMethod(self,m):
    print m
    return m
 
if __name__ == '__main__':
 
    __mixinset__ = {'Apple':({'isGift':isGift},{'eatMethod':eatMethod}),
                    'Orange':({'isGift':isGift},{'eatMethod':eatMethod}),
                    'Pear':({'notGift':notGift},{'eatMethod':eatMethod}),
                    'Banana':({'notGift':notGift},{'eatMethod':eatMethod}),
                    }
 
    apple = Apple()
    orange = Orange()
    pear = Pear()
    banana = Banana()
   
    apple.execMixIn('eatMethod','Pare')
    orange.execMixIn('eatMethod','Husk')
    pear.execMixIn('eatMethod','Pare')
    banana.execMixIn('eatMethod','Husk')
   
   
> C:\Python25\python.exe -u "D:\LeonDong\StudyStudio\Python\MixIn\minin.py"
True
True
False
False
Pare
Husk
Pare
Husk
 
 
-----Original Message-----
From: pyth...@googlegroups.com [mailto:pyth...@googlegroups.com]On Behalf Of lai yonghao
Sent: Monday, June 18, 2007 12:04 PM
To: python-...@lists.python.cn
Cc: pyth...@googlegroups.com
Subject: [SPAM] [CPyUG:27969] Mixin 扫盲班
Importance: Low

Mixin 扫盲班
赖勇浩(http://blog.csdn.net/lanphaday)

声明:本文适合初中级Python程序员阅读,另外本文措词可能会导致阅读者不适,敬请PG。

引子


嗯,为什么要谈Mixin啊?
因为出现了Mixin这样一个东西呀,就像C++社区很多人谈论template一样啊,Python社区也很多会谈论Mixin的(以后会的,嘻嘻),所以我就来凑凑热闹了。
嗯,为什么要Mixin呀?
这个,基本上已经是我这篇文章里要讲的东西了,所以,我会用本文的大部分篇幅来回答你这个超有深度的问题。现在,就开始吧~
小时候,我家开百货店,当然,也兼营水果蔬菜啊。
小时候的事,总是特别有趣,也特别的有意义,所以今天我们就以水果店开始吧~
记得,以前很多人买水果的时候,都会问我妈一个问题,就是价格了啦~但还有两个问题也经常问到哦,就是送人应该买什么水果和什么水果可以用来送人?
嗯,年青人大多都不懂这些礼节。送水果也是很讲兆头的,比如梨和香蕉一般不用来送人,因为它们意味着离别和焦躁哦;而苹果和桔子就很受欢迎,因为它们意味着平安和吉利哦~

以此为开始

新的烦恼

Pythonic的方案

除此之外
这时候,你可能会说:水果连锁店软件只是你杜撰的一个项目,Mixin有什么实际用处吗?当然有啦!其实Mixin并不是什么高阶的Python技巧,早有就很多开源项目使用这个技巧了,典型的,比如Python项目啊!在Python自带的SocketServer.py里就应用了Mixin来实现基于进程和基于线程的两种TCP/UDP服务模型,在Tkinter和Python的其它模块也可以见到它的踪迹,如果你留意的话。


# SocketServer.py 里的Mixin
class ForkingUDPServer(ForkingMixIn, UDPServer): pass
class ForkingTCPServer(ForkingMixIn, TCPServer): pass
class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
确切来说,我对Mixin来实现的水果连锁店的实现仍然相当不满意,但如果我们想要足够面向对象,也就基本上只能接受如此解决方案了。如果有一天你不能忍受每增加一种特征你就必须编写N(N>=2)个Mixin,然后都必须给已经存在的AOPB代码增加一个基类(想想,水果店卖的可不止四种水果,你会更头大),那,就考虑把OO抛弃吧!

limodou

unread,
Jun 19, 2007, 10:35:36 PM6/19/07
to python-...@lists.python.cn
On 6/20/07, 马宏亮 <mhl...@gmail.com> wrote:
> 嗯,这个说的不错,如果只是多继承是在没什么意义
> 感觉mixin作用有点像eclipse里的IAdaptable
>
Mixin与Plugin在UliPad中有区别的,Plugin是由一个调用点+实现的函数链构成。调用点需要在源码中设置,它是预知的。但是函数链则是未知的。而Mixin则可以完全未知,它是对原类的属性或方法的扩展或替换。

--
I like python!
UliPad <<The Python Editor>>: http://wiki.woodpecker.org.cn/moin/UliPad
My Blog: http://www.donews.net/limodou

Liming_Do

unread,
Jun 19, 2007, 10:50:34 PM6/19/07
to python-...@lists.python.cn
有点那个意思,于我心有戚戚焉:)
第一段代码用的元类编程,Fruit不是继承自object而是继承自type
相对来说功能强大代码简练,但是方法还是在实例化的时候确定了,不能称作mixin
是对多重继承的另一个动态增加成员的实现方法
第二段代码可以再写新的方法,加到__mixinset__中就可以调用
所以这才是我理解的能够算做是mixin的机制
-----Original Message-----
From: python-chin...@lists.python.cn [mailto:python-chin...@lists.python.cn]On Behalf Of 马宏亮
Sent: Wednesday, June 20, 2007 10:31 AM
To: python-...@lists.python.cn
Subject: [SPAM] Re: [python-chinese] [SPAM] [CPyUG:27969] Mixin 扫盲班
Importance: Low

嗯,这个说的不错,如果只是多继承是在没什么意义
感觉mixin作用有点像eclipse里的IAdaptable

在07-6-20,Liming_Do <Limi...@smics.com> 写道:



--
马宏亮

Nicholas Ding

unread,
Jun 19, 2007, 10:56:41 PM6/19/07
to pyth...@googlegroups.com
多重继承只是实现Mixin的一个手段而已,搂主自己举的水果的例子不好罢了。
关于给一个实例加入方法,这其实不算Mixin,在Python里面叫做"Monkey Patching",也就是Ruby所谓的"Open a class",都是受益于元编程模型。

_______________________________________________
python-chinese
Post: send python-...@lists.python.cn
Subscribe: send subscribe to python-chin...@lists.python.cn
Unsubscribe: send unsubscribe to   python-chin...@lists.python.cn
Detail Info: http://python.cn/mailman/listinfo/python-chinese



--
Nicholas @ Nirvana Studio
http://www.nirvanastudio.org

limodou

unread,
Jun 19, 2007, 11:08:32 PM6/19/07
to pyth...@googlegroups.com
On 6/20/07, Nicholas Ding <nicho...@gmail.com> wrote:
> 多重继承只是实现Mixin的一个手段而已,搂主自己举的水果的例子不好罢了。
> 关于给一个实例加入方法,这其实不算Mixin,在Python里面叫做"Monkey
> Patching",也就是Ruby所谓的"Open a class",都是受益于元编程模型。
>
最早我看到关于在Python中Mixin的实现的文章在这里:

http://www.linuxjournal.com/node/4540/print

Nicholas Ding

unread,
Jun 19, 2007, 11:09:56 PM6/19/07
to pyth...@googlegroups.com
我看到的有关Python的的Mixin的文章也是这个。

头太晕

unread,
Jun 19, 2007, 11:11:02 PM6/19/07
to pyth...@googlegroups.com


在07-6-20,limodou <lim...@gmail.com> 写道:
On 6/20/07, Nicholas Ding <nicho...@gmail.com> wrote:
> 多重继承只是实现Mixin的一个手段而已,搂主自己举的水果的例子不好罢了。
> 关于给一个实例加入方法,这其实不算Mixin,在Python里面叫做"Monkey
> Patching",也就是Ruby所谓的"Open a class",都是受益于元编程模型。
>
最早我看到关于在Python中Mixin的实现的文章在这里:

http://www.linuxjournal.com/node/4540/print

这个讨论主题真是精华啊...已经加星了...


Bruce Wang

unread,
Jun 20, 2007, 12:34:52 AM6/20/07
to pyth...@googlegroups.com
On 6/20/07, Liming_Do <Limi...@smics.com> wrote:
 

Banana = Fruit('Banana',(),{'isGift':lambda self: False, 'eatMethod':lambda self: 'Husk'})

这样的定义看上去很像JavaScript里面的类定义啊 :)

--
simple is good
http://brucewang.net
skype: number5
Reply all
Reply to author
Forward
0 new messages