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 相关文章推荐
使用Python编写一个在Linux下实现截图分享的脚本的教程
Apr 24 Python
在Python操作时间和日期之asctime()方法的使用
May 22 Python
python实现数值积分的Simpson方法实例分析
Jun 05 Python
Python的Django框架中URLconf相关的一些技巧整理
Jul 18 Python
Python 查看文件的读写权限方法
Jan 23 Python
python retrying模块的使用方法详解
Sep 25 Python
Python StringIO如何在内存中读写str
Jan 07 Python
Python 使用 environs 库定义环境变量的方法
Feb 25 Python
Python 实现自动登录+点击+滑动验证功能
Jun 10 Python
Python实现验证码识别
Jun 15 Python
python drf各类组件的用法和作用
Jan 12 Python
Python中三种花式打印的示例详解
Mar 19 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
火影忍者:这才是千手柱间和扉间的真正死因,角都就比较搞笑了!
2020/03/10 日漫
高亮度显示php源代码
2006/10/09 PHP
php数组中删除元素的实现代码
2012/06/22 PHP
php实现插入排序
2015/03/29 PHP
PHP处理会话函数大总结
2015/08/05 PHP
PHP的Yii框架中View视图的使用进阶
2016/03/29 PHP
Thinkphp自定义生成缩略图尺寸的方法
2019/08/05 PHP
javascript 密码强弱度检测万能插件
2009/02/25 Javascript
jqTransform form表单美化插件使用方法
2012/07/05 Javascript
js实现特定位取反原理及示例
2014/06/30 Javascript
javascript实现的平方米、亩、公顷单位换算小程序
2014/08/11 Javascript
jquery实现简单的轮换出现效果实例
2015/07/23 Javascript
javascript实现无法关闭的弹框
2016/11/27 Javascript
Three.js基础部分学习
2017/01/08 Javascript
Vue.js使用$.ajax和vue-resource实现OAuth的注册、登录、注销和API调用
2017/05/10 Javascript
Bootstrap datepicker日期选择器插件使用详解
2017/07/26 Javascript
详解vue-cli中的ESlint配置文件eslintrc.js
2017/09/25 Javascript
Vue-resource拦截器判断token失效跳转的实例
2017/10/27 Javascript
浅谈node.js 命令行工具(cli)
2018/05/10 Javascript
[01:06:19]DOTA2-DPC中国联赛定级赛 LBZS vs SAG BO3第二场 1月8日
2021/03/11 DOTA
Python中实现的RC4算法
2015/02/14 Python
python构建自定义回调函数详解
2017/06/20 Python
用Python写脚本,实现完全备份和增量备份的示例
2018/04/29 Python
python环形单链表的约瑟夫问题详解
2018/09/27 Python
Python 获取div标签中的文字实例
2018/12/20 Python
Python实现对特定列表进行从小到大排序操作示例
2019/02/11 Python
python实现门限回归方式
2020/02/29 Python
使用CSS3的ruby-position固定注音位置的用法示例
2016/07/05 HTML / CSS
营销与策划专业毕业生求职信
2013/11/01 职场文书
应届大学生求职的自我评价
2013/11/17 职场文书
酒店采购员岗位职责
2014/03/14 职场文书
新疆民族团结演讲稿
2014/08/27 职场文书
奥巴马当选演讲稿
2014/09/10 职场文书
2014乡镇领导班子四风对照检查材料思想汇报
2014/10/05 职场文书
导游词之平津战役纪念馆
2019/11/04 职场文书
详解Python如何批量采集京东商品数据流程
2022/01/22 Python