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之PyUnit单元测试实例
Oct 11 Python
Python写的一个简单监控系统
Jun 19 Python
Python实现类似jQuery使用中的链式调用的示例
Jun 16 Python
tensorflow实现对图片的读取的示例代码
Feb 12 Python
python2.7使用plotly绘制本地散点图和折线图
Apr 02 Python
python网络编程 使用UDP、TCP协议收发信息详解
Aug 29 Python
python实现的config文件读写功能示例
Sep 24 Python
CentOS7下安装python3.6.8的教程详解
Jan 03 Python
pycharm如何实现跨目录调用文件
Feb 28 Python
用python写一个带有gui界面的密码生成器
Nov 06 Python
pytorch加载语音类自定义数据集的方法教程
Nov 10 Python
pytorch 如何使用float64训练
May 24 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
jquery+php+ajax显示上传进度的多图片上传并生成缩略图代码
2014/10/15 PHP
PHP类的反射用法实例
2014/11/03 PHP
PHP读取文件的常见几种方法
2016/11/03 PHP
php使用GD2绘制几何图形示例
2017/02/15 PHP
php 多继承的几种常见实现方法示例
2019/11/18 PHP
Javascript Select操作大集合
2009/05/26 Javascript
分享一个asp.net pager分页控件
2012/01/04 Javascript
使用jquery获取网页中图片高度的两种方法
2013/09/26 Javascript
jquery text(),val(),html()方法区别总结
2013/11/04 Javascript
JQuery手速测试小游戏实现思路详解
2016/09/20 Javascript
JS实现给对象动态添加属性的方法
2017/01/05 Javascript
React创建组件的三种方式及其区别
2017/01/12 Javascript
javascript验证香港身份证的格式或真实性
2017/02/07 Javascript
javascript表达式和运算符详解
2017/02/07 Javascript
jQuery EasyUI tree增加搜索功能的实现方法
2017/04/27 jQuery
微信小程序实现选项卡功能
2020/06/19 Javascript
详解vue mixins和extends的巧妙用法
2017/12/20 Javascript
微信小程序实现人脸识别
2018/05/25 Javascript
使用koa-log4管理nodeJs日志笔记的使用方法
2018/11/30 NodeJs
Vue.js中的extend绑定节点并显示的方法
2019/06/20 Javascript
JS中如何轻松遍历对象属性的方式总结
2019/08/06 Javascript
微信小程序实现转盘抽奖
2020/09/21 Javascript
小程序实现点击tab切换左右滑动
2020/11/16 Javascript
JavaScript实现网页tab栏效果制作
2020/11/20 Javascript
Python二叉树的镜像转换实现方法示例
2019/03/06 Python
解决pycharm安装第三方库失败的问题
2020/05/09 Python
Django跨域请求原理及实现代码
2020/11/14 Python
python实现企业微信定时发送文本消息的示例代码
2020/11/24 Python
html5指南-7.geolocation结合google maps开发一个小的应用
2013/01/07 HTML / CSS
屈臣氏泰国官网:Watsons TH
2021/02/23 全球购物
大学生感恩父母演讲稿
2014/08/28 职场文书
单身证明格式样本
2015/06/15 职场文书
道士塔读书笔记
2015/06/30 职场文书
个人售房合同协议书
2016/03/21 职场文书
windows server2016安装oracle 11g的图文教程
2022/07/15 Servers
React更新渲染原理深入分析
2022/12/24 Javascript