Python面向对象运算符重载(2)

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

>>> class empty:

...     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

>>> class accesscontrol:

...     def __setattr__(self, key, value):

...         if key == 'age':

...             self.__dict__[key] = 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退而求其次的求长度,因为一个非空对象看作是真:

>>> class Truth:

...   def __len__(self): return 0

...

>>> X = Truth()

>>> if not X: print('no')

...

no

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

>>> class Truth:

...   def __bool__(self): return True

...   def __len__(self): return 0

...

>>> X = Truth()

>>> bool(X)

True

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

>>> class Truth: pass

...

>>> bool(Truth)

True

对象解析函数:__del__

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

class Life:

def __init__(self,):

print('Hello, ', name)

self.name = name

def __del__(self):

print('Goodbye', self.name)

brian = Life('Brian')

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/74e45e6e41b50d84cfbb50b978eae5cd.html