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用ConfigObj读写配置文件的实现代码
Mar 04 Python
Python爬取三国演义的实现方法
Sep 12 Python
Python爬取当当、京东、亚马逊图书信息代码实例
Dec 09 Python
Python实现螺旋矩阵的填充算法示例
Dec 28 Python
名片管理系统python版
Jan 11 Python
python进程和线程用法知识点总结
May 28 Python
解决Python内层for循环如何break出外层的循环的问题
Jun 24 Python
python 3.7.4 安装 opencv的教程
Oct 10 Python
python中seaborn包常用图形使用详解
Nov 25 Python
python模拟预测一下新型冠状病毒肺炎的数据
Feb 01 Python
Django用数据库表反向生成models类知识点详解
Mar 25 Python
Opencv中cv2.floodFill算法的使用
Jun 18 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从csv文件读取数据并输出到网页的方法
2015/03/14 PHP
PHP生成条形码大揭秘
2015/09/24 PHP
PHP数组基本用法与知识点总结
2020/06/02 PHP
php实现简易计算器
2020/08/28 PHP
屏蔽F1~F12的快捷键的js函数
2010/05/06 Javascript
JavaScript聚焦于第一个字段的代码
2010/10/15 Javascript
JS幻灯片可循环播放可平滑旋转带滚动导航(自写)
2013/08/05 Javascript
浏览器的JavaScript引擎的识别方法
2013/10/20 Javascript
setInterval与clearInterval的使用示例代码
2014/01/28 Javascript
基于javascript实现图片懒加载
2016/01/05 Javascript
EasyUI折叠表格层次显示detailview详解及实例
2016/12/28 Javascript
浅谈regExp的test方法取得的值变化的原因及处理方法
2017/03/01 Javascript
详解Angular2中Input和Output用法及示例
2017/05/21 Javascript
js匿名函数使用&传参(实例)
2017/09/08 Javascript
原生JS实现ajax与ajax的跨域请求实例
2017/12/01 Javascript
webpack 打包压缩js和css的方法示例
2018/03/20 Javascript
微信小程序上传图片到php服务器的方法
2019/05/23 Javascript
如何使用CSS3+JQuery实现悬浮墙式菜单
2019/06/18 jQuery
原生javascript实现类似vue的数据绑定功能示例【观察者模式】
2020/02/24 Javascript
python入门教程之识别验证码
2017/03/04 Python
使用Python写一个小游戏
2018/04/02 Python
Python将DataFrame的某一列作为index的方法
2018/04/08 Python
如何在Django中添加没有微秒的 DateTimeField 属性详解
2019/01/30 Python
jupyter notebook 中输出pyecharts图实例
2020/04/23 Python
Python中利用LSTM模型进行时间序列预测分析的实现
2019/07/26 Python
CSS3 text shadow字体阴影效果
2016/01/08 HTML / CSS
HTML 5.1来了 9月份正式发布 更新内容预览
2016/04/26 HTML / CSS
Solaris操作系统的线程机制
2012/12/23 面试题
如何用JQuery进行表单验证
2013/05/29 面试题
2014年便民服务中心工作总结
2014/12/20 职场文书
2015年医院科室工作总结范文
2015/05/26 职场文书
2016年第32个教师节致辞
2015/11/26 职场文书
《圆的周长》教学反思
2016/02/17 职场文书
解析redis hash应用场景和常用命令
2021/08/04 Redis
Python使用MapReduce进行简单的销售统计
2022/04/22 Python
linux目录管理方法介绍
2022/06/01 Servers