Python面向对象运算符重载
运算符重载的概念如下:[*] 运算符重载让类拦截常规的Python运算;
[*] 类可重载所有Python表达式运算符;
[*] 类也可重载打印、函数调用、属性点号运算等内置运算;
[*] 重载是类实例的行为想内置类型;
[*] 重载是通过提供特殊名称的类方法来实现的;
常见的运算符重载方法
方法重载调用__init__构造函数对象建立:X =>所有重载方法的名称前后都有两个下划线字符,以便把同类中定义的变量名区别开来。构造函数和表达式:__init__和__sub__
[*]
>>>>
[*] ... def __init__(self, start):
[*] ... self.data = start
[*] ... def __sub__(self, other):
[*] ... return Number(self.data - other)
[*] ...
[*] >>> X = Number(5)
[*] >>> Y = X - 2
[*] >>> Y
[*] <__main__.Number object at 0x10224d550>
[*] >>> Y.data
[*] 3
索引和分片: __getitem__和__setitem__
基本索引
[*]
>>>>
[*] ... def __getitem__(self, item):
[*] ... return item ** 2
[*] ...
[*] >>>
[*] >>> for i in range(5):
[*] ... I = Index()
[*] ... print(I, end=' ')
[*] ...
[*] 0 1 4 9 16
切片索引
[*]
>>>>
[*] ... data =
[*] ... def __getitem__(self, item):
[*] ... print('getitem: ', item)
[*] ... return self.data
[*] ... def __setitem__(self, key, value):
[*] ... self.data = value
[*] ...
[*] >>> X = Index()
[*] >>> print(X)
[*] getitem:slice(1, 4, None)
[*]
[*] >>> X = (1, 1, 1)
[*] >>> print(X)
[*] getitem:slice(1, 4, None)
[*]
索引迭代:__getitem__
如果重载了这个方法,for循环每次循环时都会调用类的getitem方法;
[*]
>>>>
[*] ... def __getitem__(self, item):
[*] ... return self.data.upper()
[*] ...
[*] >>>
[*] >>> X = stepper()
[*] >>> X.data = 'ansheng'
[*] >>> for item in X:
[*] ... print(item)
[*] ...
[*] A
[*] N
[*] S
[*] H
[*] E
[*] N
[*] G
迭代器对象:__iter__和__next__
[*]
>>>>
[*] ... def __init__(self, start, stop):
[*] ... self.value = start - 1
[*] ... self.stop = stop
[*] ... def __iter__(self):
[*] ... return self
[*] ... def __next__(self):
[*] ... if self.value == self.stop:
[*] ... raise StopIteration
[*] ... self.value += 1
[*] ... return self.value ** 2
[*] ...
[*] >>> for i in Squares(1, 5):
[*] ... print(i)
[*] ...
[*] 1
[*] 4
[*] 9
[*] 16
[*] 25
成员关系:__contains__、__iter__和__getitem__
[*] class Iters:
[*] def __init__(self, value):
[*] self.data = value
[*]
[*] def __getitem__(self, item):
[*] print('get[%s]' % item, end='')
[*] return self.data
[*]
[*] def __iter__(self):
[*] print('iter>==', end='')
[*] self.ix = 0
[*] return self
[*]
[*] def __next__(self):
[*] print('next:', end='')
[*] if self.ix == len(self.data): raise StopIteration
[*] item = self.data
[*] self.ix += 1
[*] return item
[*]
[*] def __contains__(self, item):
[*] print('contains: ', end=' ')
[*] return item in self.data
[*]
[*]
[*] X = Iters()
[*] print(3 in X)
[*] for i in X:
[*] print(i, end='|')
[*]
[*] print()
[*] print(list(map(bin, X)))
[*]
[*] I = iter(X)
[*] while True:
[*] try:
[*] print(next(I), end=' @')
[*] except StopIteration as e:
[*] break
属性引用:__getattr__和__setattr__
当通过未定义的属性名称和实例通过点号进行访问时,就会用属性名称作为字符串调用这个方法,但如果类使用了继承,并且在超类中可以找到这个属性,那么就不会触发。
[*]
>>>>
[*] ... def __getattr__(self, item):
[*] ... if item == 'age':
[*] ... return 40
[*] ... else:
[*] ... raise AttributeError(item)
[*] ...
[*] >>>
[*] >>> x = empty()
[*] >>> print(x.age)
[*] 40
[*] >>> print(x.name)
[*] Traceback (most recent call last):
[*] File "<stdin>", line 1, in <module>
[*] File "<stdin>", line 6, in __getattr__
[*] AttributeError: name
[*]
>>>>
[*] ... def __setattr__(self, key, value):
[*] ... if key == 'age':
[*] ... self.__dict__ = value
[*] ... else:
[*] ... raise AttributeError(key + ' not allowed')
[*] ...
[*] >>>
[*] >>> x = accesscontrol()
[*] >>> x.age = 40
[*] >>> print(x.age)
[*] 40
[*] >>> x.name = 'Hello'
[*] Traceback (most recent call last):
[*] File "<stdin>", line 1, in <module>
[*] File "<stdin>", line 6, in __setattr__
[*] AttributeError: name not allowed
__repr__和__str__会返回字符串表达式
__repr__和__str__都是为了更友好的显示,具体来说,如果在终端下print(Class)则会调用__repr__,非终端下会调用__str__方法,且这两个方法只能返回字符串;
[*] class adder:
[*] def __init__(self, value=0):
[*] self.data = value
[*]
[*] def __add__(self, other):
[*] self.data += other
[*]
[*] def __repr__(self):
[*] return 'addrepr(%s)' % self.data
[*]
[*] def __str__(self):
[*] return 'N: %s' % self.data
[*]
[*]
[*] x = adder(2)
[*] x + 1
[*] print(x)
[*] print((str(x), repr(x)))
右侧加法和原处加法: __radd__和__iadd__
只有当+右侧的对象是类实例,而左边对象不是类实例的时候,Python才会调用__radd__
[*] class Commuter:
[*] def __init__(self, val):
[*] self.val = val
[*]
[*] def __add__(self, other):
[*] print('add', self.val, other)
[*] return self.val + other
[*]
[*] def __radd__(self, other):
[*] print('radd', self.val, other)
[*] return other + self.val
[*]
[*]
[*] x = Commuter(88)
[*] y = Commuter(99)
[*] print(x + 1)
[*] print('')
[*] print(1 + y)
[*] print('')
[*] print(x + y)
使用__iadd__进行原处加法
[*] class Number:
[*] def __init__(self, val):
[*] self.val = val
[*]
[*] def __iadd__(self, other):
[*] self.val += other
[*] return self
[*]
[*]
[*] x = Number(5)
[*] x += 1
[*] x += 1
[*] print(x.val)
[*]
[*]
[*] class Number:
[*] def __init__(self, val):
[*] self.val = val
[*]
[*] def __add__(self, other):
[*] return Number(self.val + other)
[*]
[*]
[*] x = Number(5)
[*] x += 1
[*] x += 1
[*] print(x.val)
Call表达式:__call__
当调用类实例时执行__call__方法
[*] class Callee:
[*] def __call__(self, *args, **kwargs):
[*] print('Callee:', args, kwargs)
[*]
[*]
[*] C = Callee()
[*] C(1, 2, 3)
[*] C(1, 2, 3, x=1, y=2, z=3)
[*]
[*]
[*] class Prod:
[*] def __init__(self, value):
[*] self.value = value
[*]
[*] def __call__(self, other):
[*] return self.value * other
[*]
[*]
[*] x = Prod(3)
[*] print(x(3))
[*] print(x(4))
比较:__lt__,__gt__和其他方法
类可以定义方法来捕获所有的6种比较运算符:<、>、<=、>=、==和!=
[*] class C:
[*] data = 'spam'
[*]
[*] def __gt__(self, other):
[*] return self.data > other
[*]
[*] def __lt__(self, other):
[*] return self.data < other
[*]
[*] x = C()
[*] print(x > 'han')
[*] print(x < 'han')
布尔值测试:bool和len
[*] class Truth:
[*] def __bool__(self):
[*] return True
[*]
[*]
[*] X = Truth()
[*] if X: print('yes')
[*]
[*]
[*] class Truth:
[*] def __bool__(self):
[*] return False
[*]
[*] X = Truth()
[*] print(bool(X))
如果没有这个方法,Python退而求其次的求长度,因为一个非空对象看作是真:
[*]
>>>>
[*] ... def __len__(self): return 0
[*] ...
[*] >>> X = Truth()
[*] >>> if not X: print('no')
[*] ...
[*] no
如果两个方法都有,__bool__会胜过__len__:
[*]
>>>>
[*] ... def __bool__(self): return True
[*] ... def __len__(self): return 0
[*] ...
[*] >>> X = Truth()
[*] >>> bool(X)
[*] True
如果两个方法都没有定义,对象毫无疑义的看作为真:
[*]
>>>>
[*] ...
[*] >>> bool(Truth)
[*] True
对象解析函数:__del__
每当实例产生时,就会调用init构造函数,每当实例空间被收回时,它的对立面__del__,也就是解析函数,就会自动执行;
[*] class Life:
[*] def __init__(self, name='unknown'):
[*] print('Hello, ', name)
[*] self.name = name
[*]
[*] def __del__(self):
[*] print('Goodbye', self.name)
[*]
[*]
[*] brian = Life('Brian')
[*] brian = 'loretta'
页:
[1]