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 自动提交和抓取网页
Jul 13 Python
python中类变量与成员变量的使用注意点总结
Apr 29 Python
python itchat实现微信好友头像拼接图的示例代码
Aug 14 Python
python对list中的每个元素进行某种操作的方法
Jun 29 Python
selenium python 实现基本自动化测试的示例代码
Feb 25 Python
很酷的python表白工具 你喜欢我吗
Apr 11 Python
pycharm软件实现设置自动保存操作
Jun 08 Python
Python虚拟环境的创建和使用详解
Sep 07 Python
如何快速一次性卸载所有python包(第三方库)呢
Oct 20 Python
Python环境配置实现pip加速过程解析
Nov 27 Python
python_tkinter弹出对话框创建
Mar 20 Python
python3 字符串str和bytes相互转换
Mar 23 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 strlen mb_strlen计算中英文混排字符串长度
2009/07/10 PHP
PHP 工厂模式使用方法
2010/05/18 PHP
php 无限级分类,超级简单的无限级分类,支持输出树状图
2014/06/29 PHP
Zend Framework教程之Zend_Config_Ini用法分析
2016/03/23 PHP
CI框架简单邮件发送类实例
2016/05/18 PHP
php基于websocket搭建简易聊天室实践
2016/10/24 PHP
JavaScript 全角转半角部分
2009/10/28 Javascript
js本身的局限性 别让javascript做太多事
2010/03/23 Javascript
Grid得到选择行数据的方法总结
2011/01/17 Javascript
让你的博客飘雪花超出屏幕依然看得见
2013/01/04 Javascript
Jquery+CSS3实现一款简洁大气带滑动效果的弹出层
2013/05/15 Javascript
图片上传插件jquery.uploadify详解
2013/11/15 Javascript
JS获得浏览器版本和操作系统版本的例子
2014/05/13 Javascript
javascript 事件处理示例分享
2014/12/31 Javascript
浅析Bootstrap缩略图组件与警示框组件
2016/04/29 Javascript
JavaScript交换两个变量方法实例
2019/11/25 Javascript
解决小程序无法触发SESSION问题
2020/02/03 Javascript
JS实现无限轮播无倒退效果
2020/09/21 Javascript
在Python中使用PIL模块对图片进行高斯模糊处理的教程
2015/05/05 Python
编写Python脚本把sqlAlchemy对象转换成dict的教程
2015/05/29 Python
代码讲解Python对Windows服务进行监控
2018/02/11 Python
selenium+python实现自动登录脚本
2018/04/22 Python
解决matplotlib库show()方法不显示图片的问题
2018/05/24 Python
解决python 未发现数据源名称并且未指定默认驱动程序的问题
2018/12/07 Python
pyqt5 comboBox获得下标、文本和事件选中函数的方法
2019/06/14 Python
python破解bilibili滑动验证码登录功能
2019/09/11 Python
python下载库的步骤方法
2019/10/12 Python
详解KMP算法以及python如何实现
2020/09/18 Python
Python实现网络聊天室的示例代码(支持多人聊天与私聊)
2021/01/27 Python
简述进程的启动、终止的方式以及如何进行进程的查看
2013/07/12 面试题
护士个人自我鉴定
2014/03/24 职场文书
《海底世界》教学反思
2014/04/16 职场文书
中学生评语大全
2014/04/18 职场文书
项目建议书模板
2014/05/12 职场文书
2015年体检中心工作总结
2015/05/27 职场文书
2016廉洁教育心得体会
2016/01/20 职场文书