Python中的数学运算操作符使用进阶


Posted in Python onJune 20, 2016

Python中对象的行为是由它的类型 (Type) 决定的。所谓类型就是支持某些特定的操作。数字对象在任何编程语言中都是基础元素,支持加、减、乘、除等数学操作。
Python的数字对象有整数和浮点数,支持各种数学操作,比如+, -,*, /等。 没有这些操作符,程序中只能使用函数调用的方式进行数学运算,比如add(2, 3), sub(5, 2)。
程序中操作符的作用与普通数学操作的用法是一致的,使用中更加简便直观。Python中,这些操作符实现是通过定义一些object的特殊方法实现的,比如object.__add__()和object.__sub__()。如果用户在自己定义类时实现上述特殊方法,可以使自定义类的对象支持相应的数学操作,从而模拟数字对象的行为。这其实是达到了操作符重载的效果。

这里通过实现一个具有支持加法运算的中文数字类说明如何在Python中实现一个支持常见的数学操作。ChineseNumber类的基本定义如下。

class ChineseNumber:
  def __init__(self, n):
    self.num = n
    self.alphabet = [u'零', u'一', u'二', u'三', u'四', 
      u'五', u'六', u'七', u'八', u'九', u'十']

  def __str__(self):
    sign = '负' if self.num < 0 else ''
    return sign + ''.join([self.alphabet[int(s)] for s in str(abs(self.num))])

  def __repr__(self):
    return self.__str__()

目前,实现的效果是这样的:

>>> a = ChineseNumber(2)
>>> a  #调用a.__repr__()
二
>>> print(a)  #调用a.__str__()

二

一般数学操作符
定义类时,实现__add__()方法,可以给这个类增加+操作符。给ChineseNumber增加如下方法:

def __add__(self, other):
    if type(other) is ChineseNumber:
      return ChineseNumber(self.num + other.num)
    elif type(other) is int:
      return ChineseNumber(self.num + other)
    else:
      return NotImplemented

这时ChineseNumber的对象就可以使用+了。

>>> a, b = ChineseNumber(2), ChineseNumber(10)
>>> a + b
十二
>>> a + 5
七
>>> a + 3.7
TypeError: unsupported operand type(s) for +: 'ChineseNumber' and 'float'

对于+,a + b相当于调用a.__add__(b). 类似地,可以定义其他数学操作符,见下表。

object.__add__(self, other): +
object.__sub__(self, other): -
object.__mul__(self, other): *
object.__matmul__(self, other): @
object.__truediv__(self, other): /
object.__floordiv__(self, other): //
object.__mod__(self, other): %
object.__divmod__(self, other): divmod, divmod(a, b) = (a/b, a%b)
object.__pow__(self, other[,modulo]): **, pow()
object.__lshift__(self, other): <<
object.__rshift__(self, other): >>
object.__and__(self, other): &
object.__xor__(self, other): ^
object.__or__(self, other): |

操作数反转的数学操作符 (Reflected/Swapped Operand)

>>> 2 + a
TypeError: unsupported operand type(s) for +: 'int' and 'ChineseNumber'

2是整数类型,它的__add__()方法不支持ChineseNumber类的对象,所以出现了上述错误。定义操作数反转的数学操作符可以解决这个问题。给ChineseNumber类添加__radd__()方法,实现操作数反转的+运算。

def __radd__(self, other):
    return self.__add__(other)

对于a + b,如果a没有定义__add__()方法,Python尝试调用b的__radd__()方法。此时,a + b相当于调用b.__radd__(a)。

>>> a = ChineseNumber(2)
>>> 2 + a
四

类似地,可以定义其他操作数反转的数学操作符,见下表。

object.__radd__(self, other): +
object.__rsub__(self, other): -
object.__rmul__(self, other): *
object.__rmatmul__(self, other): @
object.__rtruediv__(self, other): /
object.__rfloordiv__(self, other): //
object.__rmod__(self, other): %
object.__rdivmod__(self, other): divmod, divmod(a, b) = (b/a, b%a)
object.__rpow__(self, other[,modulo]): **, pow()
object.__rlshift__(self, other): <<
object.__rrshift__(self, other): >>
object.__rand__(self, other): &
object.__rxor__(self, other): ^
object.__ror__(self, other): |

运算赋值操作符
运算赋值操作符使用单个操作符完成运算和赋值操作,比如a += b相当于调用a = a + b。为ChineseNumber增加__iadd__()方法,可以实现+=操作符。

def __iadd__(self, other):
    if type(other) is ChineseNumber:
      self.num += other.num
      return self
    elif type(other) is int:
      self.num += other
      return self
    else:
      return NotImplemented

此时,

>>> a, b = ChineseNumber(2), ChineseNumber(10)
>>> a += b
>>> a
十二
>>> a + 7
>>> a
十九

类似地,可以定义其他运算赋值操作符,见下表。

object.__iadd__(self, other): +=
object.__isub__(self, other): -=
object.__imul__(self, other): *=
object.__imatmul__(self, other): @=
object.__itruediv__(self, other): /=
object.__ifloordiv__(self, other): //=
object.__imod__(self, other): %=
object.__ipow__(self, other[,modulo]): **=
object.__ilshift__(self, other): <<=
object.__irshift__(self, other): >>=
object.__iand__(self, other): &=
object.__ixor__(self, other): ^=
object.__ior__(self, other): |=

一元数学操作符
一元数学操作符是只有一个操作数的运算,比如取负数的操作符-。-对应的特殊函数是__neg__()。为ChineseNumber添加__neg__()方法,

def __neg__(self):
    return ChineseNumber(-self.num)

此时,ChineseNumber对象就支持-操作了。

>>> a = ChineseNumber(5)
>>> -a
负五

其他一元运算符见下表。

object.__neg__(self): -
object.__pos__(self): +
object.__abs__(self): abs()
object.__invert__(self): ~
object.__complex__(self): complex()
object.__int__(self): int()
object.__float__(self): float()
object.__round__(self): round()
object.__index__(self): operator.index()
Python 相关文章推荐
利用Python3分析sitemap.xml并抓取导出全站链接详解
Jul 04 Python
对python模块中多个类的用法详解
Jan 10 Python
使用Python3内置文档高效学习以及官方中文文档
May 19 Python
python同步windows和linux文件
Aug 29 Python
Python实现括号匹配方法详解
Feb 10 Python
Python for循环搭配else常见问题解决
Feb 11 Python
tensorflow保持每次训练结果一致的简单实现
Feb 17 Python
如何实现一个python函数装饰器(Decorator)
Oct 12 Python
matplotlib部件之套索Lasso的使用
Feb 24 Python
深入探讨opencv图像矫正算法实战
May 21 Python
Python实现双向链表基本操作
May 25 Python
python单向链表实例详解
May 25 Python
Python中在for循环中嵌套使用if和else语句的技巧
Jun 20 #Python
解析Python中的生成器及其与迭代器的差异
Jun 20 #Python
Python判断列表是否已排序的各种方法及其性能分析
Jun 20 #Python
Python编程中装饰器的使用示例解析
Jun 20 #Python
12步入门Python中的decorator装饰器使用方法
Jun 20 #Python
深入学习Python中的装饰器使用
Jun 20 #Python
Python中Iterator迭代器的使用杂谈
Jun 20 #Python
You might like
PHP 和 MySQL 开发的 8 个技巧
2007/01/02 PHP
如何解决phpmyadmin导入数据库文件最大限制2048KB
2015/10/09 PHP
总结AJAX相关JS代码片段和浏览器模型
2007/08/15 Javascript
jQuery中setTimeout的几种使用方法小结
2013/04/07 Javascript
uploadify在Firefox下丢失session问题的解决方法
2013/08/07 Javascript
Jquery图片延迟加载插件jquery.lazyload.js的使用方法
2014/05/21 Javascript
jquery用data方法获取某个元素上的事件
2014/06/23 Javascript
jquery显示隐藏元素的实现代码
2016/05/19 Javascript
打造自己的jQuery插件入门教程
2016/09/23 Javascript
Vue.js基础知识小结
2017/01/13 Javascript
微信JSSDK调用微信扫一扫功能的方法
2017/07/25 Javascript
微信小程序中使用ECharts 异步加载数据实现图表功能
2018/07/13 Javascript
JavaScript实现正则去除a标签并保留内容的方法【测试可用】
2018/07/18 Javascript
实例详解vue中的$root和$parent
2019/04/29 Javascript
微信小程序实现同一页面取值的方法分析
2019/04/30 Javascript
JavaScript和TypeScript中的void的具体使用
2019/09/12 Javascript
微信小程序 button样式设置为图片的方法
2020/06/19 Javascript
如何构建一个Vue插件并生成npm包
2020/10/26 Javascript
[00:32]2018DOTA2亚洲邀请赛VGJ.T出场
2018/04/03 DOTA
快速查询Python文档方法分享
2017/12/27 Python
Python利用多线程同步锁实现多窗口订票系统(推荐)
2019/12/22 Python
使用Django清空数据库并重新生成
2020/04/03 Python
python3 googletrans超时报错问题及翻译工具优化方案 附源码
2020/12/23 Python
python实现图片转字符画的完整代码
2021/02/21 Python
我们是伦敦女孩:WalG
2018/01/08 全球购物
毕业生大学生活自我总结
2014/01/31 职场文书
小学语文国培感言
2014/03/04 职场文书
英文求职信范文
2014/05/23 职场文书
派出所副所长四风问题个人整改措施思想汇报
2014/10/13 职场文书
员工福利申请报告
2015/05/15 职场文书
Go语言使用select{}阻塞main函数介绍
2021/04/25 Golang
如何用PHP websocket实现网页实时聊天
2021/05/26 PHP
Nginx四层负载均衡的配置指南
2021/06/11 Servers
Java网络编程之UDP实现原理解析
2021/09/04 Java/Android
九大龙王魂骨,山龙王留下躯干骨,榜首死的最憋屈(被捏碎)
2022/03/18 国漫
vue3使用vuedraggable实现拖拽功能
2022/04/06 Vue.js