追寻真理之美

——此人一贯挖坑不填

用户操作
[即时聊天] [发私信] [加为好友]
智拙
智拙的公告
Python 2.4
最近评论
zhangjunhd:理解
ccat:错误我改过来了,PDF版和TeX版文件也重新上传了,但是HTML压缩包不知道怎么删除重新上传。
ccat:多谢提醒,我晚上回去看看。
ccat:杨编辑好:)
linux:嘿嘿,刘鑫老师,我是博文的linux!
文章分类
收藏
    相册
    文章插图
    朋友
    bobo,家有三猫
    Fire,永远比我严肃那么一点点
    lee
    limodou,NewEdit之父(RSS)
    Playyuer,近来可好(RSS)
    Ricky的私人领地
    Vicko,聪明的孩子,提着易碎的灯笼
    Vickox,一个人,两枝笔
    冰菊叮叮的绮季
    卡卡和哆哆的小窝,从这里开始,我的人生不再与以前相同
    寻梦的blog
    小尹,成功人士将来时。
    岑心的小天地
    暖暖,美丽的文字,总是让我深陷其中。
    梅劲松,Python经典实践(RSS)
    欢欢小师妹(RSS)
    灰色咆哮,彩色收藏
    蔚蔚,祝你幸福快乐
    西区故事,有故事的男人。
    面面的金鱼缸,内有美人鱼,生人勿近
    饼干~大饼~素饼饼~
    收藏
    cavingdeep,颇有知音之感(RSS)
    Guoly工作室,提供WinCVS中文教程
    Robert Chen(RSS)
    深入浅出,诲人不倦,可为人师也——项武义先生网站
    透明,熊节
    网络项目
    .net 中文讨论组
    Firebird项目的CVS
    Python2.3指南
    Python中文社区
    Python文档中文化项目
    啄木鸟
    啄木鸟的老巢
    我的新家
    休闲收藏
    办公室Party
    廖添丁
    恶搞圣斗士
    魔塔
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 Python的可调用对象收藏

    新一篇: CLISP Tutorial 中英对照版(一) | 旧一篇: 今天真是个好日子……

     

    __call__

    Python中有一个有趣的语法,只要定义类型的时候,实现__call__函数,这个类型就成为可调用的。

    换句话说,我们可以把这个类型的对象当作函数来使用,相当于重载了括号运算符。

    例如,现在我们要计算重力环境下的自然落体位移。我们知道Sy=(gt**2)/2,那么,我们可以建立一个函数:

    def g_dpm(t):

    return (9.8*t**2)/2

    我们都知道,地球表面的重力加速度约等于9.8m/s**2,这个函数实在没什么技术含量。

    慢,头儿说了,我要算的是火星啊¥%#

    呃……你能说人家无理取闹么?EAFIFA足球里,我还见过微重力模式的球场,总之,在计算机程序里,很多超现实的需求都有可能。

    恩,最简单的办法当然是:

    def mar_g_dpm(t):

    return (3.92*t**2)/2 #火星表面的重力加速度约等于地球表面的2/5

    不过,你真的能保证下次那个可爱的策划不会再设计一个金星场景?或者木星?或者该死的大魔导师行会开始出售新的魔法卷轴——重力操控?

    当然,我们可以这样设计这个函数:

    def g_dpm(g, t):

    return (g*t**2)/2

    但是g相对于t,是一个稳定得多的数量,基本上,在一次相关运算中,g可以当作常量。那么,一个可调用对象也许更适合。下面定义这样一个类型:

    class g_dpm(object):

    def __init__(self, g):

    self.g = g

    def __call__(self, t):

    return (self.g*t**2)/2

    计算地球场景的时候,我们就可以令e_dpm = g_dpm(9.8)s = e_dpm(t)。同样的方式,可以很容易的生成其他重力环境下的自由落地公式。

    Command模式和委托/事件

    CommandGOF的《设计模式》中23种设计模式之一。简单来说,就是把行为对象化,这个过程在Python中是很自然的——Python里的函数本来就是一种对象么。如果只是传递函数对象,用不着C/C++中胆战心惊的函数指针或Boost那样华丽的仿函数类型——这倒不是说Python就比C/C++好,设计目标不同。如果需要更复杂的Command,我们就要用到回调对象了。

    事件(event)是framework中常用的设计,通常来讲,事件应该满足以下的要求:

    1、有默认行为,如果没有任何事件响应,至少保证事件发生时不会有错误,通常这时什么也不做。

    2、允许为一个事件注册多个实现,这个倒不是必须的,但是常见的framework都实现了这一功能。

    3、可以注销事件响应,这个就需要第一和第二点的支持。

    4、针对不同的事件,可以传入对应的参数,通常这个功能是通过一个object *void *之类的指针(对象引用)传入一个结构体来实现的。

    .net中为了支持这个功能,专门定制了一个特殊类型——Delegate,它对应C#的关键字delegate。在python中么……这个东西其实很容易实现,事实上,我就在我的程序中使用了下面的代码:

    class Delegate(set):

    def __call__(self, *arg)

    for foo in self:

    foo(*arg)

    简单吧,利用参数列表,我们还很容的实现了不同事件可能的参数定义要求。当然,这与通常见到的event(sender, args)形式并不冲突。其实,更进一步的话,我们要实现并发响应也很容易:

    import thread

    class MTDelegate(set):

    def __call__(self , *args)

    for foo in sender:

    thread.start_new_thread(foo, args)



    我们还可以让它返回事件响应值的一个序列:



    class FunDelegate(set):

    def __call__(self, *arg)

    return [foo(*arg) for foo in self]

    __call__是一个简单而有趣的功能,利用它,我们可以更灵活的设计代码。当然,重载运算符(从C++的观点来看,这里是重载了括号)总是存在一个风险——它太过有趣,所以容易被滥用。在使用之前,我们最好确认,这个功能用在这里,确实有助于我们的工作,而不是画蛇添足。

    发表于 @ 2006年02月24日 16:33:00|编辑

    新一篇: CLISP Tutorial 中英对照版(一) | 旧一篇: 今天真是个好日子……

    评论:没有评论。

    Csdn Blog version 3.1a
    Copyright © 智拙