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引用(import)文件夹下的py文件的方法
Aug 26 Python
Python的另外几种语言实现
Jan 29 Python
PyQt实现界面翻转切换效果
Apr 20 Python
Python 实现字符串中指定位置插入一个字符
May 02 Python
Python3.6.0+opencv3.3.0人脸检测示例
May 25 Python
python3将视频流保存为本地视频文件
Jun 20 Python
实例分析python3实现并发访问水平切分表
Sep 29 Python
对Python 内建函数和保留字详解
Oct 15 Python
python3常用的数据清洗方法(小结)
Oct 31 Python
关于Pytorch的MLP模块实现方式
Jan 07 Python
python文件及目录操作代码汇总
Jul 08 Python
使用tkinter实现三子棋游戏
Feb 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
elgg 获取文件图标地址的方法
2010/03/20 PHP
具有时效性的php加密解密函数代码
2013/06/19 PHP
smarty模板中使用get、post、request、cookies、session变量的方法
2014/04/24 PHP
Laravel 5.3 学习笔记之 错误&日志
2016/08/28 PHP
浅谈PHP的数据库接口和技术
2016/12/09 PHP
PHP图像处理技术实例总结【绘图、水印、验证码、图像压缩】
2018/12/08 PHP
javascript 继承实现方法
2009/08/26 Javascript
ASP.NET jQuery 实例16 通过控件CustomValidator验证RadioButtonList
2012/02/03 Javascript
javascript定时变换图片实例代码
2013/03/17 Javascript
JavaScript中的类(Class)详细介绍
2014/12/30 Javascript
jquery图片滚动放大代码分享(1)
2015/08/25 Javascript
超精准的javascript验证身份证号的具体实现方法
2015/11/18 Javascript
JavaScript编写Chrome扩展实现与浏览器的交互及时间通知
2016/05/16 Javascript
Bootstrap基本组件学习笔记之面板(14)
2016/12/08 Javascript
Vue2.x中的父子组件相互通信的实现方法
2017/05/02 Javascript
React Hooks 实现和由来以及解决的问题详解
2020/01/17 Javascript
[01:23]2014DOTA2国际邀请赛 球迷无处不在Ti现场世界杯受关注
2014/07/10 DOTA
[00:27]DOTA2荣耀之路2:Patience from zhou!
2018/05/24 DOTA
[02:03]风行者至宝清风环佩外观展示
2020/09/05 DOTA
一个基于flask的web应用诞生 bootstrap框架美化(3)
2017/04/11 Python
Python模拟用户登录验证
2017/09/11 Python
python机器学习之随机森林(七)
2018/03/26 Python
Python3之简单搭建自带服务器的实例讲解
2018/06/04 Python
python遍历小写英文字母的方法
2019/01/02 Python
对Python w和w+权限的区别详解
2019/01/23 Python
详解Python基础random模块随机数的生成
2019/03/23 Python
Django 通过JS实现ajax过程详解
2019/07/30 Python
python实现比对美团接口返回数据和本地mongo数据是否一致示例
2019/08/09 Python
python使用PIL剪切和拼接图片
2020/03/23 Python
python递归函数求n的阶乘,优缺点及递归次数设置方式
2020/04/02 Python
python实现三种随机请求头方式
2021/01/05 Python
详解如何使用Pytest进行自动化测试
2021/01/14 Python
html5中的input新属性range使用记录
2014/09/05 HTML / CSS
美国家居用品和厨具购物网站:DealsDot
2019/10/07 全球购物
2014年科普工作总结
2014/12/06 职场文书
PyTorch 如何自动计算梯度
2021/05/23 Python