【搬家】【Python】一瞥 Python 定制类的强大功能

来源:互联网 发布:sql server pdf 编辑:程序博客网 时间:2024/05/29 16:04

本文最早于 2014年1月1日于本人个人博客(http://mooowooo.tk)发表,现博客搬家至此,转载请注明出处。


这篇是对 Python 里关于定制类部分学习后的一个简单总结,主要是通过例子来告诉大家定制类的强大。关于定制类的知识,我是在《Python 核心编程》里的 13.13 节学习的。书中有一个关于时间计算的例子,原书例子的代码我就不放上来了,有兴趣的朋友可以去找到本书来学习,我这里给出我对这个例子的修改和分析,来告诉大家为什么我说定制类十分强大。

Talk is week, let me show you my code.

class TimeCount(object):    def __init__(self, minutes = 0, hours = 0, days = 0):        if days <> 0 :        self.days = days        if hours < 24 and hours >= 0 :            self.hours = hours        elif hours >= 24 :            self.days += hours / 24            self.hours = hours % 24        elif hours < 0 :            self.hours = 0        if minutes < 60 and minutes >= 0 :            self.minutes = minutes        elif minutes >= 60 :            self.hours += minutes / 60            self.minutes = minutes % 60        elif minutes < 0 :            self.minutes = 0    def __str__(self) :        return '%d days %d hours %d minutes' % (self.days, self.hours, self.minutes)    __repr__ = __str__    def __add__(self, other) :        return self.__class__(self.minutes + other.minutes, self.hours + other.hours, self.days + other.days)    def __iadd__(self, other) :        self.days += other.days        self.hours += other.hours        self.minutes += other.minutes        return self    def __div__(self, other):        return 'Error !'if __name__ == '__main__':    a = TimeCount(10, 2, 3)    b = TimeCount(7, 4)    c = TimeCount(175, 69)    print a    print b    print c    print a + b    print a + c    print a += c    print b < c    print a / c    #print b % c

这段代码很简单,写得也很丑陋,不过已经足够表达 Python 里定制类的强大了。首先,我们创建了一个名为 TimeCount 的类,在实例化时,根据其传入的参数数量和每个参数的进制计算方式,为该实例计算出最合理的表现形式。比如,在实例化a b c 3个实例后,将其打印到屏幕上的效果是:

3 days 2 hours 10 minutes0 days 4 hours 7 minutes2 days 23 hours 55 minutes

跟之前实例化时传入的参数并不相同,因为在 __init__ 函数里,我们对传入的参数进行了进制换算和进位。当然,这并不是我们要讲的 Python 定制类的厉害之处。真正厉害的地方在下面的两句a + ba + c

当我们在执行到 print a + b 时,Python 了解到,a 实例的值为 3 days 2 hours 10 minutesb 实例的值为 0 days 4 hours 7 minutes。因为我们在类中对 + 操作做了重载,所以 Python 计算出最终结果是3 days 6 hours 17 minutes,于是 Python 就顺利将该结果打印到了屏幕上。

同理,在计算 print a + c 时,因为实例 c 在实例化时已经经过换算得到他的值为 2 days 23 hours 55 minutes,那么与 a 做计算时得到的结果是什么呢?最开始,我以为 Python 会笨笨的得到5 days 25 hours 65 minutes 的错误结果。但是没想到,Python 直接给出了 6 days 2 hours 5 minutes 的正确答案。这一下子让我想到,之前学习 Common Lisp 时,看到过的一个小彩蛋,就是在 Common Lisp 里的 FORMAT 指令可以将一个随意输入的数字转换成为英文标准写法[1]。虽然这两个东西想起来好像没什么联系,但是一下子激发了我一窥究竟的欲望。于是打上断点——对了,我用的是 PyCharm,强烈推荐各位写 Python 的朋友试试,记得付费买正版——点击 debug ,开始一步步查看计算过程。

原来,Python 在计算时并不是讲两个实例的值单纯的加总后输出,而是调用 __init__ 创建一个——原谅我不知道怎么称呼——匿名实例。并将两个实例的值加总后传入进行进制换算。并把计算的结果输出,然后就丢弃掉这个临时创建的匿名实例释放资源。所以,当计算逻辑准确无误的写到__init__ 中时,Python 总能给出正确的结果。想调戏 Python 对我来说还为时尚早。

同样的,因为我们也对 += 操作符进行了重载,所以 下面一句 print a += c 也会得出相同的结果,只是这个结果被赋值给了实例a,同时计算过程也略有不同,有兴趣的朋友可以自己去 debug 一下。

我不知道其他 OO语言 是否也有此特性 因为还没去实验,不过回头想想,其实也并不是多么神奇的东西,一句话概括就是:申请了对用户不可见的匿名实例参与计算并得出当前算法下的正确结果。

大概应该就是这么回事,如有错漏,还望各位看官指出。

[1]: 比如输入 format nil "-r" 1606938044258990275541962092 你将得到 one octillion six hundred six septllion nino hundred thirty-eight sextillion forty-four quintillion two hundred fifty-eight quadrillion nine hundred ninety trillion two hundred seventy-five billion five hundred forty-one million nine hundred sixty-two thousand ninety-two 这个答案,数一数,绝对正确。
0 0