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实现多线程采集的2个代码例子
Jul 07 Python
Python方法的延迟加载的示例代码
Dec 18 Python
Python 变量类型详解
Oct 10 Python
python判断一个数是否能被另一个整数整除的实例
Dec 12 Python
python用fsolve、leastsq对非线性方程组求解
Dec 15 Python
对Python 检查文件名是否规范的实例详解
Jun 10 Python
python使用正则表达式(Regular Expression)方法超详细
Dec 30 Python
python opencv实现图片缺陷检测(讲解直方图以及相关系数对比法)
Apr 07 Python
500行python代码实现飞机大战
Apr 24 Python
Pandas实现一列数据分隔为两列
May 18 Python
python selenium xpath定位操作
Sep 01 Python
python数据可视化使用pyfinance分析证券收益示例详解
Nov 20 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 第二节 数据类型之数值型
2012/04/28 PHP
php gzip压缩输出的实现方法
2013/04/27 PHP
php 读取输出其他文件的实现方法
2016/07/26 PHP
Laravel框架实现定时发布任务的方法
2018/08/16 PHP
判断多个input type=file是否有已经选择好文件的代码
2012/05/23 Javascript
java与javascript之间json格式数据互转介绍
2013/10/29 Javascript
jQuery表格列宽可拖拽改变且兼容firfox
2014/09/03 Javascript
详细分析使用AngularJS编程中提交表单的方式
2015/06/19 Javascript
JavaScript中的return语句简单介绍
2015/12/07 Javascript
jQuery 选择器(61种)整理总结
2016/09/26 Javascript
Bootstrap Table使用心得总结
2016/11/29 Javascript
vue2.0实战之使用vue-cli搭建项目(2)
2017/03/27 Javascript
js 获取html5的data属性实现方法
2017/07/28 Javascript
微信小程序媒体组件详解(视频,音乐,图片)
2017/09/19 Javascript
vue页面离开后执行函数的实例
2018/03/13 Javascript
JavaScript文本特效实例小结【3个示例】
2018/12/22 Javascript
微信小程序中网络请求缓存的解决方法
2019/12/29 Javascript
原生js实现文件上传、下载、封装等实例方法
2020/01/05 Javascript
[54:53]2014 DOTA2国际邀请赛中国区预选赛 LGD-GAMING VS CIS 第二场
2014/05/23 DOTA
详解Python中的__new__()方法的使用
2015/04/09 Python
Python3实现从指定路径查找文件的方法
2015/05/22 Python
基于python绘制科赫雪花
2018/06/22 Python
Python使用ConfigParser模块操作配置文件的方法
2018/06/29 Python
python爬虫超时的处理的实例
2018/12/19 Python
使用OpenCV实现仿射变换—平移功能
2019/08/29 Python
css3+jq创作含苞待放的荷花
2014/02/20 HTML / CSS
CSS3自定义滚动条样式的示例代码
2017/08/21 HTML / CSS
html5页面结构_动力节点Java学院整理
2017/07/10 HTML / CSS
优秀员工年终发言演讲稿
2014/01/01 职场文书
社团活动总结
2014/04/28 职场文书
推荐信格式要求
2014/05/09 职场文书
商铺门前三包责任书
2014/07/25 职场文书
上课说话检讨书
2015/01/27 职场文书
大四学生个人总结
2015/02/15 职场文书
公司禁烟通知
2015/04/23 职场文书
金砖之国观后感
2015/06/11 职场文书