Python运算符重载详解及实例代码


Posted in Python onMarch 07, 2017

Python运算符重载

      Python语言提供了运算符重载功能,增强了语言的灵活性,这一点与C++有点类似又有些不同。鉴于它的特殊性,今天就来讨论一下Python运算符重载。

      Python语言本身提供了很多魔法方法,它的运算符重载就是通过重写这些Python内置魔法方法实现的。这些魔法方法都是以双下划线开头和结尾的,类似于__X__的形式,python通过这种特殊的命名方式来拦截操作符,以实现重载。当Python的内置操作运用于类对象时,Python会去搜索并调用对象中指定的方法完成操作。

       类可以重载加减运算、打印、函数调用、索引等内置运算,运算符重载使我们的对象的行为与内置对象的一样。Python在调用操作符时会自动调用这样的方法,例如,如果类实现了__add__方法,当类的对象出现在+运算符中时会调用这个方法。

常见运算符重载方法

方法名 重载说明 运算符调用方式
__init__ 构造函数 对象创建: X = Class(args)
__del__ 析构函数 X对象收回
__add__/__sub__ 加减运算  X+Y, X+=Y/X-Y, X-=Y
__or__ 运算符| X|Y, X|=Y
_repr__/__str__ 打印/转换 print(X)、repr(X)/str(X)
__call__ 函数调用 X(*args, **kwargs)
__getattr__ 属性引用 X.undefined
__setattr__ 属性赋值 X.any=value
__delattr__ 属性删除 del X.any
__getattribute__ 属性获取 X.any
__getitem__ 索引运算 X[key],X[i:j]
__setitem__ 索引赋值 X[key],X[i:j]=sequence
__delitem__ 索引和分片删除 del X[key],del X[i:j]
__len__ 长度 len(X)
__bool__ 布尔测试 bool(X)
__lt__, __gt__,  __le__, __ge__,  __eq__, __ne__ 特定的比较 依次为XY,X=Y,  X==Y,X!=Y  注释:(lt: less than, gt: greater than,    le: less equal, ge: greater equal,    eq: equal, ne: not equal  )
__radd__ 右侧加法 other+X
__iadd__ 实地(增强的)加法 X+=Y(or else __add__)
__iter__, __next__ 迭代 I=iter(X), next()
__contains__ 成员关系测试 item in X(X为任何可迭代对象)
__index__ 整数值 hex(X), bin(X),  oct(X)
__enter__, __exit__ 环境管理器 with obj as var:
__get__, __set__,  __delete__ 描述符属性 X.attr, X.attr=value, del X.attr
__new__ 创建 在__init__之前创建对象

   下面对常用的运算符方法的使用进行一下介绍。

构造函数和析构函数:__init__和__del__

       它们的主要作用是进行对象的创建和回收,当实例创建时,就会调用__init__构造方法。当实例对象被收回时,析构函数__del__会自动执行。

>>> class Human(): 
...   def __init__(self, n): 
...     self.name = n 
...       print("__init__ ",self.name) 
...   def __del__(self): 
...     print("__del__") 
...  
>>> h = Human('Tim') 
__init__ Tim 
>>> h = 'a' 
__del__

加减运算:__add__和__sub__

       重载这两个方法就可以在普通的对象上添加+-运算符操作。下面的代码演示了如何使用+-运算符,如果将代码中的__sub__方法去掉,再调用减号运算符就会出错。

>>> class Computation(): 
...   def __init__(self,value): 
...     self.value = value 
...   def __add__(self,other): 
...     return self.value + other 
...   def __sub__(self,other): 
...     return self.value - other 
...  
>>> c = Computation(5) 
>>> c + 5 
10 
>>> c - 3 
2

对象的字符串表达形式:__repr__和__str__

       这两个方法都是用来表示对象的字符串表达形式:print()、str()方法会调用到__str__方法,print()、str()和repr()方法会调用__repr__方法。从下面的例子可以看出,当两个方法同时定义时,Python会优先搜索并调用__str__方法。

>>> class Str(object): 
...   def __str__(self): 
...     return "__str__ called"   
...   def __repr__(self): 
...     return "__repr__ called" 
...  
>>> s = Str() 
>>> print(s) 
__str__ called 
>>> repr(s) 
'__repr__ called' 
>>> str(s) 
'__str__ called'

索引取值和赋值:__getitem__, __setitem__

       通过实现这两个方法,可以通过诸如 X[i] 的形式对对象进行取值和赋值,还可以对对象使用切片操作。

>>> class Indexer: 
  data = [1,2,3,4,5,6] 
  def __getitem__(self,index): 
    return self.data[index] 
  def __setitem__(self,k,v): 
    self.data[k] = v 
    print(self.data) 
>>> i = Indexer() 
>>> i[0] 
1 
>>> i[1:4] 
[2, 3, 4] 
>>> i[0]=10 
[10, 2, 3, 4, 5, 6]

设置和访问属性:__getattr__、__setattr__

       我们可以通过重载__getattr__和__setattr__来拦截对对象成员的访问。__getattr__在访问对象中不存在的成员时会自动调用。__setattr__方法用于在初始化对象成员的时候调用,即在设置__dict__的item时就会调用__setattr__方法。具体例子如下:

class A(): 
  def __init__(self,ax,bx): 
    self.a = ax 
    self.b = bx 
  def f(self): 
    print (self.__dict__) 
  def __getattr__(self,name): 
    print ("__getattr__") 
  def __setattr__(self,name,value): 
    print ("__setattr__") 
    self.__dict__[name] = value 
 
a = A(1,2) 
a.f() 
a.x 
a.x = 3 
a.f()

     上面代码的运行结果如下,从结果可以看出,访问不存在的变量x时会调用__getattr__方法;当__init__被调用的时候,赋值运算也会调用__setattr__方法。

__setattr__ 
__setattr__ 
{'a': 1, 'b': 2} 
__getattr__ 
__setattr__ 
{'a': 1, 'x': 3, 'b': 2}

迭代器对象: __iter__,  __next__

       Python中的迭代,可以直接通过重载__getitem__方法来实现,看下面的例子。

>>> class Indexer: 
...   data = [1,2,3,4,5,6] 
...   def __getitem__(self,index): 
...       return self.data[index] 
...  
>>> x = Indexer() 
>>> for item in x: 
...   print(item) 
...  
1 
2 
3 
4 
5 
6

      通过上面的方法是可以实现迭代,但并不是最好的方式。Python的迭代操作会优先尝试调用__iter__方法,再尝试__getitem__。迭代环境是通过iter去尝试寻找__iter__方法来实现,而这种方法返回一个迭代器对象。如果这个方法已经提供,Python会重复调用迭代器对象的next()方法,直到发生StopIteration异常。如果没有找到__iter__,Python才会尝试使用__getitem__机制。下面看一下迭代器的例子。

class Next(object): 
  def __init__(self, data=1): 
    self.data = data 
  def __iter__(self): 
    return self 
  def __next__(self): 
    print("__next__ called") 
    if self.data > 5: 
      raise StopIteration 
    else: 
      self.data += 1 
      return self.data 
for i in Next(3): 
  print(i) 
print("-----------") 
n = Next(3) 
i = iter(n) 
while True: 
  try: 
    print(next(i)) 
  except Exception as e: 
    break

   程序的运行结果如下:

__next__ called 
4 
__next__ called 
5 
__next__ called 
6 
__next__ called 
----------- 
__next__ called 
4 
__next__ called 
5 
__next__ called 
6 
__next__ called

    可见实现了__iter__和__next__方法后,可以通过for in的方式迭代遍历对象,也可以通过iter()和next()方法迭代遍历对象。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

Python 相关文章推荐
python多线程操作实例
Nov 21 Python
Python抽象类的新写法
Jun 18 Python
分析并输出Python代码依赖的库的实现代码
Aug 09 Python
基于Python代码编辑器的选用(详解)
Sep 13 Python
机器学习python实战之手写数字识别
Nov 01 Python
浅谈python中对于json写入txt文件的编码问题
Jun 07 Python
Flask和Django框架中自定义模型类的表名、父类相关问题分析
Jul 19 Python
python在html中插入简单的代码并加上时间戳的方法
Oct 16 Python
Python中按键来获取指定的值
Mar 02 Python
Python 获取windows桌面路径的5种方法小结
Jul 15 Python
python实现的登录与提交表单数据功能示例
Sep 25 Python
使用python实现希尔、计数、基数基础排序的代码
Dec 25 Python
利用Python中的pandas库对cdn日志进行分析详解
Mar 07 #Python
python下os模块强大的重命名方法renames详解
Mar 07 #Python
深入理解python中的atexit模块
Mar 07 #Python
Python 备份程序代码实现
Mar 06 #Python
Python与Java间Socket通信实例代码
Mar 06 #Python
python使用arcpy.mapping模块批量出图
Mar 06 #Python
python与php实现分割文件代码
Mar 06 #Python
You might like
php数组函数序列之asort() - 对数组的元素值进行升序排序,保持索引关系
2011/11/02 PHP
php在线代理转向代码
2012/05/05 PHP
JS 自定义带默认值的函数
2011/07/21 Javascript
jQuery实现跨域
2015/02/03 Javascript
js点击列表文字对应该行显示背景颜色的实现代码
2015/08/05 Javascript
javascript与Python快速排序实例对比
2015/08/10 Javascript
基于jQuery仿淘宝产品图片放大镜代码分享
2020/06/23 Javascript
js判断日期时间有效性的方法
2015/10/24 Javascript
js从外部获取图片的实现方法
2016/08/05 Javascript
javascript实现的左右无缝滚动效果
2016/09/19 Javascript
js实现手机拍照上传功能
2017/01/17 Javascript
详解angular用$sce服务来过滤HTML标签
2017/04/11 Javascript
socket.io学习教程之深入学习篇(三)
2017/04/29 Javascript
Iphone手机、安卓手机浏览器控制默认缩放大小的方法总结(附代码)
2017/08/18 Javascript
浅谈针对Vue相同路由不同参数的刷新问题
2018/09/29 Javascript
Node.js 多线程完全指南总结
2019/03/27 Javascript
小程序中设置缓存过期的实现方法
2020/01/14 Javascript
antd-日历组件,前后禁止选择,只能选中间一部分的实例
2020/10/29 Javascript
一起深入理解js中的事件对象
2021/02/06 Javascript
python网页请求urllib2模块简单封装代码
2014/02/07 Python
Python多线程编程(六):可重入锁RLock
2015/04/05 Python
Python中pygame安装方法图文详解
2015/11/11 Python
python编码总结(编码类型、格式、转码)
2016/07/01 Python
Python实现好友全头像的拼接实例(推荐)
2017/06/24 Python
详解Python中for循环是如何工作的
2017/06/30 Python
解决Python plt.savefig 保存图片时一片空白的问题
2019/01/10 Python
pytorch 图像中的数据预处理和批标准化实例
2020/01/15 Python
英国最大的纸工艺品商店:CraftStash
2018/12/01 全球购物
Java文件和目录(IO)操作
2014/08/26 面试题
配件采购员岗位职责
2013/12/03 职场文书
马智宇婚礼主持词
2014/03/22 职场文书
小学生交通安全寄语
2015/02/27 职场文书
鲁冰花观后感
2015/06/10 职场文书
新郎婚礼致辞
2015/07/27 职场文书
运动会闭幕式致辞
2015/07/29 职场文书
班主任远程培训研修日志
2015/11/13 职场文书