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的Urllib库的基本使用教程
Apr 30 Python
浅谈python抛出异常、自定义异常, 传递异常
Jun 20 Python
python中实现将多个print输出合成一个数组
Apr 19 Python
Python wxPython库消息对话框MessageDialog用法示例
Sep 03 Python
python找出一个列表中相同元素的多个索引实例
Jun 11 Python
Python自定义聚合函数merge与transform区别详解
May 26 Python
使用python实现名片管理系统
Jun 18 Python
解决python3输入的坑——input()
Dec 05 Python
Python与C/C++的相互调用案例
Mar 04 Python
python爬不同图片分别保存在不同文件夹中的实现
Apr 02 Python
Python还能这么玩之用Python做个小游戏的外挂
Jun 04 Python
python使用matplotlib绘制图片时x轴的刻度处理
Aug 30 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
Dwz与thinkphp整合下的数据导出到Excel实例
2014/12/04 PHP
IE innerHTML,outerHTML所引起的问题
2009/06/04 Javascript
解决js数据包含加号+通过ajax传到后台时出现连接错误
2013/08/01 Javascript
jquery浏览器滚动加载技术实现方案
2014/06/03 Javascript
jQuery.lazyload+masonry改良图片瀑布流代码
2014/06/20 Javascript
网站接入QQ登录的两种方法
2014/07/22 Javascript
javascript根据时间生成m位随机数最大13位
2014/10/30 Javascript
jQuery Raty 一款不错的星级评分插件
2016/08/24 Javascript
Vue过滤器的用法和自定义过滤器使用
2017/02/08 Javascript
基于JavaScript实现类名的添加与移除
2017/04/23 Javascript
vue-cli单页应用改成多页应用配置详解
2017/07/14 Javascript
JavaScript hasOwnProperty() 函数实例详解
2017/08/04 Javascript
浅谈ES6新增的数组方法和对象
2017/08/08 Javascript
JS函数节流和防抖之间的区分和实现详解
2019/01/11 Javascript
微信小程序实现手势滑动卡片效果
2019/08/26 Javascript
vue2.* element tabs tab-pane 动态加载组件操作
2020/07/19 Javascript
Python随机生成数模块random使用实例
2015/04/13 Python
玩转python爬虫之正则表达式
2016/02/17 Python
python获取list下标及其值的简单方法
2016/09/12 Python
详解Python if-elif-else知识点
2018/06/11 Python
Python 可变类型和不可变类型及引用过程解析
2019/09/27 Python
详解使用python3.7配置开发钉钉群自定义机器人(2020年新版攻略)
2020/04/01 Python
Python Selenium模块安装使用教程详解
2020/07/09 Python
Rockport乐步美国官网:风靡美国的白宫鞋
2016/11/24 全球购物
高职助产应届生自荐信
2013/09/24 职场文书
小学教师岗位职责
2013/11/25 职场文书
公司年会晚宴演讲稿
2014/01/06 职场文书
质量承诺书怎么写
2014/05/24 职场文书
工程造价专业求职信
2014/07/17 职场文书
我们的节日元宵活动方案
2014/08/23 职场文书
党员群众路线个人整改措施思想汇报
2014/10/12 职场文书
2014年驻村干部工作总结
2014/11/17 职场文书
致运动员赞词
2015/07/22 职场文书
情人节单身感言
2015/08/03 职场文书
python实战之用emoji表情生成文字
2021/05/08 Python
python 实现两个变量值进行交换的n种操作
2021/06/02 Python