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 相关文章推荐
在Django框架中运行Python应用全攻略
Jul 17 Python
Python实现配置文件备份的方法
Jul 30 Python
实例讲解Python中函数的调用与定义
Mar 14 Python
Python探索之ModelForm代码详解
Oct 26 Python
Python编程argparse入门浅析
Feb 07 Python
pandas的qcut()方法详解
Jul 06 Python
使用Fabric自动化部署Django项目的实现
Sep 27 Python
Django框架序列化与反序列化操作详解
Nov 01 Python
Python调用Windows API函数编写录音机和音乐播放器功能
Jan 05 Python
Tensorflow--取tensorf指定列的操作方式
Jun 30 Python
Python3 用matplotlib绘制sigmoid函数的案例
Dec 11 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 处理上百万条的数据库如何提高处理查询速度
2010/02/08 PHP
The specified CGI application misbehaved by not returning a complete set of HTTP headers
2011/03/31 PHP
深入解析PHP中逗号与点号的区别
2013/08/05 PHP
php中Session的生成机制、回收机制和存储机制探究
2014/08/19 PHP
实例讲解如何在PHP的Yii框架中进行错误和异常处理
2016/03/17 PHP
利用php做服务器和web前端的界面进行交互
2016/10/31 PHP
php 计算两个时间相差的天数、小时数、分钟数、秒数详解及实例代码
2016/11/09 PHP
封装好的省市地区联动控件附下载
2007/08/13 Javascript
jQuery中innerHeight()方法用法实例
2015/01/19 Javascript
JavaScript第一篇之实现按钮全选、功能
2016/08/21 Javascript
jquery自定义表单验证插件
2016/10/12 Javascript
详解如何使用webpack打包Vue工程
2017/05/27 Javascript
[js高手之路]原型式继承与寄生式继承详解
2017/08/28 Javascript
JavaScript数组,JSON对象实现动态添加、修改、删除功能示例
2018/05/26 Javascript
React SSR样式及SEO的实践
2018/10/22 Javascript
elementUI select组件默认选中效果实现的方法
2019/03/25 Javascript
vue和better-scroll实现列表左右联动效果详解
2019/04/29 Javascript
node静态服务器实现静态读取文件或文件夹
2019/12/03 Javascript
vue实现瀑布流组件滑动加载更多
2020/03/10 Javascript
javascript递归函数定义和用法示例分析
2020/07/22 Javascript
[01:34]DAC2018主赛事第四日五佳镜头 Gh巨牙海民助Miracle-死里逃生
2018/04/07 DOTA
Python笔记(叁)继续学习
2012/10/24 Python
python将图片文件转换成base64编码的方法
2015/03/14 Python
python中MethodType方法介绍与使用示例
2017/08/03 Python
python字符串的方法与操作大全
2018/01/30 Python
Python实现的文本对比报告生成工具示例
2018/05/22 Python
pandas 条件搜索返回列表的方法
2018/10/30 Python
PyQt5中QSpinBox计数器的实现
2021/01/18 Python
英国领先的野生鸟类食品供应商:GardenBird
2018/08/09 全球购物
一套SQL笔试题
2016/08/14 面试题
大学生的网络创业计划书
2013/12/26 职场文书
工人先进事迹材料
2014/12/26 职场文书
财务人员岗位职责
2015/02/03 职场文书
2015年公司保安年终工作总结
2015/05/14 职场文书
电影开国大典观后感
2015/06/04 职场文书
PyTorch梯度裁剪避免训练loss nan的操作
2021/05/24 Python