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/ironpython:从入门到精通
Oct 02 Python
利用Python脚本实现ping百度和google的方法
Jan 24 Python
Python实现生成随机数据插入mysql数据库的方法
Dec 25 Python
Python简单实现控制电脑的方法
Jan 22 Python
解决python给列表里添加字典时被最后一个覆盖的问题
Jan 21 Python
Python HTML解析器BeautifulSoup用法实例详解【爬虫解析器】
Apr 05 Python
对Python中class和instance以及self的用法详解
Jun 26 Python
python如何从文件读取数据及解析
Sep 19 Python
如何基于python实现脚本加密
Dec 28 Python
PyCharm设置Ipython交互环境和宏快捷键进行数据分析图文详解
Apr 23 Python
Python  word实现读取及导出代码解析
Jul 09 Python
使用python求斐波那契数列中第n个数的值示例代码
Jul 26 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
PHP5中新增stdClass 内部保留类
2011/06/13 PHP
php一行代码获取文件后缀名实例分析
2014/11/12 PHP
jquery插件 autoComboBox 下拉框
2010/12/22 Javascript
在js中判断checkboxlist(.net控件客户端id)是否有选中
2013/04/11 Javascript
用正则表达式替换图片地址img标签
2013/11/22 Javascript
javascript事件冒泡详解和捕获、阻止方法
2014/04/12 Javascript
JS使用oumousemove和oumouseout动态改变图片显示的方法
2015/03/31 Javascript
JavaScript实现自动消除按钮功能的方法
2015/08/05 Javascript
jQuery通过ajax请求php遍历json数组到table中的代码(推荐)
2016/06/12 Javascript
jQuery Easyui Datagrid实现单行的上移下移及保存移动的结果
2016/08/15 Javascript
js实现按钮控制带有停顿效果的图片滚动
2016/08/30 Javascript
浅谈EasyUi ComBotree树修改 父节点选择的问题
2016/11/07 Javascript
js实现背景图自适应窗口大小
2017/01/10 Javascript
分分钟玩转Vue.js组件(二)
2017/03/01 Javascript
windows下vue.js开发环境搭建教程
2017/03/20 Javascript
基于原生js运动方式关键点的总结(推荐)
2017/10/01 Javascript
原生JS实现 MUI导航栏透明渐变效果
2017/11/07 Javascript
基于jquery实现九宫格拼图小游戏
2018/11/30 jQuery
JavaScript中AOP的实现与应用
2019/05/06 Javascript
jQuery层叠选择器用法实例分析
2019/06/28 jQuery
[00:12]2018DOTA2亚洲邀请赛SOLO赛 MidOne是否中单第一人?
2018/04/05 DOTA
Python常见加密模块用法分析【MD5,sha,crypt模块】
2017/05/24 Python
解读python logging模块的使用方法
2018/04/17 Python
pandas 数据归一化以及行删除例程的方法
2018/11/10 Python
Python图像滤波处理操作示例【基于ImageFilter类】
2019/01/03 Python
python实现矩阵打印
2019/03/02 Python
Python根据服务获取端口号的方法
2019/09/25 Python
PyCharm设置Ipython交互环境和宏快捷键进行数据分析图文详解
2020/04/23 Python
Happy Socks英国官网:购买五颜六色的袜子
2020/11/03 全球购物
检查机关党的群众路线个人整改措施
2014/10/04 职场文书
解除劳动合同证明书模板
2014/11/20 职场文书
2014年创卫工作总结
2014/11/24 职场文书
Nest.js参数校验和自定义返回数据格式详解
2021/03/29 Javascript
pytorch交叉熵损失函数的weight参数的使用
2021/05/24 Python
Win11 Build 21996.1 Dev版怎么样? win11系统截图欣赏
2021/11/21 数码科技
JavaCV实现照片马赛克效果
2022/01/22 Java/Android