Python面向对象运算符重载

运算符重载的概念如下:

  1. 运算符重载让类拦截常规的Python运算;
  2. 类可重载所有Python表达式运算符;
  3. 类也可重载打印、函数调用、属性点号运算等内置运算;
  4. 重载是类实例的行为想内置类型;
  5. 重载是通过提供特殊名称的类方法来实现的;

常见的运算符重载方法

方法 重载 调用
__init__ 构造函数 对象建立:X = Class(args)
__del__ 解析函数 X对象收回
__add__ 运算符+ 如果没有__iadd__,X+Y,X+=Y
__or__ 运算符或 如果没有__ior__
__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],没__iter__时的for循环和其他迭代器
__setitem__ 索引赋值语句 X[key]=value,X[i:k]=sequence
__delitem__ 索引和分片删除 del X[key], del X[i:j]
__len__ 长度 len(X),如果没有__bool__,真值测试
__bool__ 布尔测试 bool(X),真测试
__lt__,__gt__,__le__,__ge__,__eq__,__ne__ 特定的比较 XY…,x>
__radd__ 右侧加法 Other + X
__iadd__ 增强的加法 X += Y
__iter__,__next__ 迭代环境 I=iter(X),next(I)
__contains__ 成员关系测试 item in X(任何可迭代对象)
__index__ 整数值 hex(X),bin(X),oct(X),o[X],O[X:]
__enter__,__exit__ 环境管理器 with obj as var:
__get__,__set__,__delete__ 描述符属性 X.attr,X.attr=Value,del X.attr
__new__ 创建 在__init__之前创建对象

所有重载方法的名称前后都有两个下划线字符,以便把同类中定义的变量名区别开来。

构造函数和表达式:__init__和__sub__

  1. >>> class Number:
  2. ...   def __init__(self, start):
  3. ...     self.data = start
  4. ...   def __sub__(self, other):
  5. ...     return Number(self.data - other)
  6. ...
  7. >>> X = Number(5)
  8. >>> Y = X - 2
  9. >>> Y
  10. <__main__.Number object at 0x10224d550>
  11. >>> Y.data
  12. 3

索引和分片: __getitem__和__setitem__

基本索引

  1. >>> class Index:
  2. ...     def __getitem__(self, item):
  3. ...         return item ** 2
  4. ...
  5. >>>
  6. >>> for i in range(5):
  7. ...     I = Index()
  8. ...     print(I[i], end=‘ ‘)
  9. ...
  10. 0 1 4 9 16

切片索引

  1. >>> class Index:
  2. ...   data = [5, 6, 7, 8, 9]
  3. ...   def __getitem__(self, item):
  4. ...     print(‘getitem: ‘, item)
  5. ...     return self.data[item]
  6. ...   def __setitem__(self, key, value):
  7. ...     self.data[key] = value
  8. ...
  9. >>> X = Index()
  10. >>> print(X[1:4])
  11. getitem:  slice(1, 4, None)
  12. [6, 7, 8]
  13. >>> X[1:4] = (1, 1, 1)
  14. >>> print(X[1:4])
  15. getitem:  slice(1, 4, None)
  16. [1, 1, 1]

索引迭代:__getitem__

如果重载了这个方法,for循环每次循环时都会调用类的getitem方法;

  1. >>> class stepper:
  2. ...     def __getitem__(self, item):
  3. ...         return self.data[item].upper()
  4. ...
  5. >>>
  6. >>> X = stepper()
  7. >>> X.data = ‘ansheng‘
  8. >>> for item in X:
  9. ...     print(item)
  10. ...
  11. A
  12. N
  13. S
  14. H
  15. E
  16. N
  17. G

迭代器对象:__iter__和__next__

  1. >>> class Squares:
  2. ...   def __init__(self, start, stop):
  3. ...         self.value = start - 1
  4. ...         self.stop = stop
  5. ...   def __iter__(self):
  6. ...         return self
  7. ...   def __next__(self):
  8. ...         if self.value == self.stop:
  9. ...             raise StopIteration
  10. ...         self.value += 1
  11. ...         return self.value ** 2
  12. ...
  13. >>> for i in Squares(1, 5):
  14. ...   print(i)
  15. ...
  16. 1
  17. 4
  18. 9
  19. 16
  20. 25

成员关系:__contains__、__iter__和__getitem__

  1. class Iters:
  2. def __init__(self, value):
  3. self.data = value
  4. def __getitem__(self, item):
  5. print(‘get[%s]‘ % item, end=‘‘)
  6. return self.data[item]
  7. def __iter__(self):
  8. print(‘iter>==‘, end=‘‘)
  9. self.ix = 0
  10. return self
  11. def __next__(self):
  12. print(‘next:‘, end=‘‘)
  13. if self.ix == len(self.data): raise StopIteration
  14. item = self.data[self.ix]
  15. self.ix += 1
  16. return item
  17. def __contains__(self, item):
  18. print(‘contains: ‘, end=‘ ‘)
  19. return item in self.data
  20. X = Iters([1, 2, 3, 4, 5])
  21. print(3 in X)
  22. for i in X:
  23. print(i, end=‘|‘)
  24. print([i ** 2 for i in X])
  25. print(list(map(bin, X)))
  26. I = iter(X)
  27. while True:
  28. try:
  29. print(next(I), end=‘ @‘)
  30. except StopIteration as e:
  31. break

属性引用:__getattr__和__setattr__

当通过未定义的属性名称和实例通过点号进行访问时,就会用属性名称作为字符串调用这个方法,但如果类使用了继承,并且在超类中可以找到这个属性,那么就不会触发。

  1. >>> class empty:
  2. ...     def __getattr__(self, item):
  3. ...         if item == ‘age‘:
  4. ...             return 40
  5. ...         else:
  6. ...             raise AttributeError(item)
  7. ...
  8. >>>
  9. >>> x = empty()
  10. >>> print(x.age)
  11. 40
  12. >>> print(x.name)
  13. Traceback (most recent call last):
  14. File "<stdin>", line 1, in <module>
  15. File "<stdin>", line 6, in __getattr__
  16. AttributeError: name
  1. >>> class accesscontrol:
  2. ...     def __setattr__(self, key, value):
  3. ...         if key == ‘age‘:
  4. ...             self.__dict__[key] = value
  5. ...         else:
  6. ...             raise AttributeError(key + ‘ not allowed‘)
  7. ...
  8. >>>
  9. >>> x = accesscontrol()
  10. >>> x.age = 40
  11. >>> print(x.age)
  12. 40
  13. >>> x.name = ‘Hello‘
  14. Traceback (most recent call last):
  15. File "<stdin>", line 1, in <module>
  16. File "<stdin>", line 6, in __setattr__
  17. AttributeError: name not allowed

__repr__和__str__会返回字符串表达式

__repr__和__str__都是为了更友好的显示,具体来说,如果在终端下print(Class)则会调用__repr__,非终端下会调用__str__方法,且这两个方法只能返回字符串;

  1. class adder:
  2. def __init__(self, value=0):
  3. self.data = value
  4. def __add__(self, other):
  5. self.data += other
  6. def __repr__(self):
  7. return ‘addrepr(%s)‘ % self.data
  8. def __str__(self):
  9. return ‘N: %s‘ % self.data
  10. x = adder(2)
  11. x + 1
  12. print(x)
  13. print((str(x), repr(x)))

右侧加法和原处加法: __radd__和__iadd__

只有当+右侧的对象是类实例,而左边对象不是类实例的时候,Python才会调用__radd__

  1. class Commuter:
  2. def __init__(self, val):
  3. self.val = val
  4. def __add__(self, other):
  5. print(‘add‘, self.val, other)
  6. return self.val + other
  7. def __radd__(self, other):
  8. print(‘radd‘, self.val, other)
  9. return other + self.val
  10. x = Commuter(88)
  11. y = Commuter(99)
  12. print(x + 1)
  13. print(‘‘)
  14. print(1 + y)
  15. print(‘‘)
  16. print(x + y)

使用__iadd__进行原处加法

  1. class Number:
  2. def __init__(self, val):
  3. self.val = val
  4. def __iadd__(self, other):
  5. self.val += other
  6. return self
  7. x = Number(5)
  8. x += 1
  9. x += 1
  10. print(x.val)
  11. class Number:
  12. def __init__(self, val):
  13. self.val = val
  14. def __add__(self, other):
  15. return Number(self.val + other)
  16. x = Number(5)
  17. x += 1
  18. x += 1
  19. print(x.val)

Call表达式:__call__

当调用类实例时执行__call__方法

  1. class Callee:
  2. def __call__(self, *args, **kwargs):
  3. print(‘Callee:‘, args, kwargs)
  4. C = Callee()
  5. C(1, 2, 3)
  6. C(1, 2, 3, x=1, y=2, z=3)
  7. class Prod:
  8. def __init__(self, value):
  9. self.value = value
  10. def __call__(self, other):
  11. return self.value * other
  12. x = Prod(3)
  13. print(x(3))
  14. print(x(4))

比较:__lt__,__gt__和其他方法

类可以定义方法来捕获所有的6种比较运算符:<、>、<=、>=、==和!=

  1. class C:
  2. data = ‘spam‘
  3. def __gt__(self, other):
  4. return self.data > other
  5. def __lt__(self, other):
  6. return self.data < other
  7. x = C()
  8. print(x > ‘han‘)
  9. print(x < ‘han‘)

布尔值测试:bool和len

  1. class Truth:
  2. def __bool__(self):
  3. return True
  4. X = Truth()
  5. if X: print(‘yes‘)
  6. class Truth:
  7. def __bool__(self):
  8. return False
  9. X = Truth()
  10. print(bool(X))

如果没有这个方法,Python退而求其次的求长度,因为一个非空对象看作是真:

  1. >>> class Truth:
  2. ...   def __len__(self): return 0
  3. ...
  4. >>> X = Truth()
  5. >>> if not X: print(‘no‘)
  6. ...
  7. no

如果两个方法都有,__bool__会胜过__len__:

  1. >>> class Truth:
  2. ...   def __bool__(self): return True
  3. ...   def __len__(self): return 0
  4. ...
  5. >>> X = Truth()
  6. >>> bool(X)
  7. True

如果两个方法都没有定义,对象毫无疑义的看作为真:

  1. >>> class Truth: pass
  2. ...
  3. >>> bool(Truth)
  4. True

对象解析函数:__del__

每当实例产生时,就会调用init构造函数,每当实例空间被收回时,它的对立面__del__,也就是解析函数,就会自动执行;

  1. class Life:
  2. def __init__(self, name=‘unknown‘):
  3. print(‘Hello, ‘, name)
  4. self.name = name
  5. def __del__(self):
  6. print(‘Goodbye‘, self.name)
  7. brian = Life(‘Brian‘)
  8. brian = ‘loretta‘
时间: 2024-10-13 16:16:27

Python面向对象运算符重载的相关文章

7Python全栈之路系列之面向对象运算符重载

Python全栈之路系列之面向对象运算符重载 运算符重载的概念如下: 运算符重载让类拦截常规的Python运算: 类可重载所有Python表达式运算符: 类也可重载打印.函数调用.属性点号运算等内置运算: 重载是类实例的行为想内置类型: 重载是通过提供特殊名称的类方法来实现的: 常见的运算符重载方法 方法 重载 调用 __init__ 构造函数 对象建立:X = Class(args) __del__ 解析函数 X对象收回 __add__ 运算符+ 如果没有__iadd__,X+Y,X+=Y _

【Python】面向对象的运算符重载

面向对象的编程中可以对运算符进行重载,使运算符可以对该类的实例进行操作. 重载方法的一般格式如下: 1 def __运算符名__(self, other): 2 运算符语句 比较常用的运算符重载有三类:二元算术运算符重载.反向算术运算符重载.比较运算符重载.一元运算符重载 1 二元算术运算符的重载: 2 方法名                  运算符和表达式      说明 3 __add__(self,rhs)        self + rhs      加法 4 __sub__(self

Python运算符重载

运算符重载是指在方法(双下划线的特殊方法)中拦截内置的操作--当类的实例出现在内置操作中,Python会自动调用自定义的方法,并且返回自定义方法的操作结果. 可以让类拦截常规的Python运算. 可调用对象:__call__() 函数:内置函数.自定义函数.def.lambda 类 类方法 函数的属性: __doc__ __name__ __dict__ __code__ __globals__ 方法的属性: __doc__ __name__ __func__ __class__ __self_

python运算符重载2

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86

Python——运算符重载(1)

运算符重载 关键概念: 1.运算符重载让类拦截常规的Python运算. 2.类可重载所有的Python表达式运算符. 3.类也可重载打印.函数调用.属性点号运算等内置运算. 4.重载使类实例的行为像内置类型. 5.重载是通过特殊名称的类方法来实现的. 运算符重载只是意味着在类方法中拦截内置的操作--当类的实例出现在内置操作中,Python自动调用你的方法,并且你的方法的返回值变成了相应操作的结果. =================================================

sdut 面向对象程序设计上机练习十一(运算符重载)

面向对象程序设计上机练习十一(运算符重载) Time Limit: 1000MS Memory limit: 65536K 题目描述 有两个矩阵a和b,均为2行3列,求两个矩阵之和.重载运算符"+",使之能用于矩阵相加.如:c=a+b. 输入 第1.2行是矩阵a的值,数据以空格分开. 第3.4行是矩阵b的值,数据以空格分开. 输出 2个矩阵a.b之和,以行列形式显示. 示例输入 2 3 4 3 5 3 4 3 1 5 4 3 示例输出 6 6 5 8 9 6 来源 #include &

Python 3 之 运算符重载详解

基础知识 实际上,"运算符重载"只是意味着在类方法中拦截内置的操作--当类的实例出现在内置操作中,Python自动调用你的方法,并且你的方法的返回值变成了相应操作的结果.以下是对重载的关键概念的复习: 运算符重载让类拦截常规的Python运算. 类可重载所有Python表达式运算符 类可以重载打印.函数调用.属性点号运算等内置运算 重载使类实例的行为像内置类型. 重载是通过特殊名称的类方法来实现的. 换句话说,当类中提供了某个特殊名称的方法,在该类的实例出现在它们相关的表达式时,Pyt

sdut 面向对象程序设计上机练习十二(运算符重载)

面向对象程序设计上机练习十二(运算符重载) Time Limit: 1000MS Memory limit: 65536K 题目描述 处理一个复数与一个double数相加的运算,结果存放在一个double型变量d1中,输出d1的值.定义Complex(复数)类,在成员函数中包含重载类型转换运算符:operator double(){return real;} 输入 输入占两行: 第1行是一个复数的实部和虚部,数据以空格分开. 第2行是一个实数. 输出 输出占一行,复数的实部和实数之和,小数点后保

面向对象程序设计上机练习十一(运算符重载)

面向对象程序设计上机练习十一(运算符重载) Time Limit: 1000MS Memory limit: 65536K 题目描述 有两个矩阵a和b,均为2行3列,求两个矩阵之和.重载运算符“+”,使之能用于矩阵相加.如:c=a+b. 输入 第1.2行是矩阵a的值,数据以空格分开. 第3.4行是矩阵b的值,数据以空格分开. 输出 2个矩阵a.b之和,以行列形式显示. 示例输入 2 3 4 3 5 3 4 3 1 5 4 3 示例输出 6 6 5 8 9 6 #include <iostream