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之集成开发环境(IDE)
Sep 12 Python
Python访问MySQL封装的常用类实例
Nov 11 Python
Python列表生成器的循环技巧分享
Mar 06 Python
python实现根据窗口标题调用窗口的方法
Mar 13 Python
Python入门教程之运算符与控制流
Aug 17 Python
利用python 更新ssh 远程代码 操作远程服务器的实现代码
Feb 08 Python
Numpy 将二维图像矩阵转换为一维向量的方法
Jun 05 Python
python 创建一个空dataframe 然后添加行数据的实例
Jun 07 Python
python3.6使用pickle序列化class的方法
Oct 22 Python
pycharm执行python时,填写参数的方法
Oct 29 Python
PyCharm-错误-找不到指定文件python.exe的解决方法
Jul 01 Python
使用Python实现微信拍一拍功能的思路代码
Jul 09 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
日本十大惊悚动漫
2020/03/04 日漫
[EPIC] Larva vs Flash ZvT @ Crossing Field [2017-10-09]
2020/03/17 星际争霸
php单例模式实现(对象只被创建一次)
2012/12/05 PHP
PHP实现采集抓取淘宝网单个商品信息
2015/01/08 PHP
php+mysqli使用面向对象方式更新数据库实例
2015/01/29 PHP
PHP基于imagick扩展实现合成图片的两种方法【附imagick扩展下载】
2017/11/14 PHP
PHP如何通过表单直接提交大文件详解
2019/01/08 PHP
浅谈javascript原型链与继承
2015/07/13 Javascript
20分钟轻松创建自己的Bootstrap站点
2016/05/12 Javascript
浅谈JavaScript 标准对象
2016/06/02 Javascript
基于JS如何实现给字符加千分符(65,541,694,158)
2016/08/03 Javascript
Vuejs第七篇之Vuejs过渡动画案例全面解析
2016/09/05 Javascript
vue实现简单实时汇率计算功能
2017/01/15 Javascript
小程序自定义单页面、全局导航栏的实现代码
2019/03/15 Javascript
vue input输入框关键字筛选检索列表数据展示
2020/10/26 Javascript
vue服务端渲染操作简单入门实例分析
2019/08/28 Javascript
详解关于Vue单元测试的几个坑
2020/04/26 Javascript
JavaScript函数重载操作实例浅析
2020/05/02 Javascript
javascript实现评分功能
2020/06/24 Javascript
win10 64bit下python NLTK安装教程
2018/09/19 Python
python zip()函数使用方法解析
2019/10/31 Python
matlab中imadjust函数的作用及应用举例
2020/02/27 Python
python绘制雷达图实例讲解
2021/01/03 Python
python解决OpenCV在读取显示图片的时候闪退的问题
2021/02/23 Python
2015年幼儿园毕业感言
2014/02/12 职场文书
国际贸易专业个人职业生涯规划
2014/02/15 职场文书
工商管理自荐书
2014/07/06 职场文书
助人为乐道德模范事迹材料
2014/08/16 职场文书
个人工作表现评价材料
2014/09/21 职场文书
对照四风自我剖析材料
2014/10/07 职场文书
毕业生评语大全
2015/01/04 职场文书
人事专员岗位职责
2015/02/03 职场文书
乡镇法制宣传日活动总结
2015/05/05 职场文书
电影开国大典观后感
2015/06/04 职场文书
Python经常使用的一些内置函数
2022/04/11 Python
app场景下uniapp的扫码记录
2022/07/23 Java/Android