Python运算符重载
1、__getattr__,__setattr__,__getattribute__等等
class A(object):
age = 43
def __init__(self):
print 'A'
self.name = 'a'
self.age = 23
def __getattr__(self, item):
if item == 'height':
print 'print my height'
return item
def __setattr__(self, key, value):
if key == 'height':
print 'set height ok'
self.__dict__[key] = value
def test(self):
print 'test'
a = A()
print a.__dict__
a.height=1
print a.height
输出:
A
{'age': 23, 'name': 'a'}
set height ok
1
当我们执行点号运算时,a.height最终会调用__getattr__,想赋值的时候会调用__setattr__。注意上面:__getattr__只能用来查询不在__dict__系统中的属性,即只拦截类和实例没有的属性,即未在类中定义的。
Python中还有一个__getattribute__特殊方法,它会拦截所有属性的获取。而且__getattribute__要比__getattr__的优先级高,当定义前者之后,后者就不起作用了。
还有一点需要注意,是关于赋值属性,__setattr__会拦截所有属性的赋值,即self.attr=value总会调用self.__setattr__(key,value),所以一定要注意该属性的编写,否则就会出现无限循环。要用self.__dict__[key] = value赋值。
说到这,我们看一个通过__setattr__和__getattr__实现的类的私有属性的方法(我们都知道python并没有提供像Java那样private等方法):
class PrivateExc(Exception):
pass
class A(object):
def __setattr__(self, key, value):
if key not in self.privates:
raise PrivateExc('{0} not in {1} '.format(key,self))
else:
self.__dict__[key] = value
class B(A):
privates = ['age']
def __init__(self,age):
self.age = age
def __getattr__(self, item):
return item
b = B(12)
b.age = 30
print b.age
b.name = 'h'
30
Traceback (most recent call last):
File "D:/Study/Programming/Python/myworks/weiborobot/__init__.py", line 32, in <module>
b.name = 'h'
File "D:/Study/Programming/Python/myworks/weiborobot/__init__.py", line 15, in __setattr__
raise PrivateExc('{0} not in {1} '.format(key,self))
__main__.PrivateExc: name not in <__main__.B object at 0x00000000025A7780>
2、类的比较
上面已经说到了,python有很多的内置运算符,我们可以进行重载。比如__lt__,__eq__,__gt__。等等,我们可以通过重载类的这些运算符,来实现我定制的功能,例子:
class Com(object):
def __init__(self,value):
self.value = value
def __eq__(self, other):
if self.value == other.value:
return 'they are same'
else:
return False
def __lt__(self, other):
if self.value < other.value:
return '{0} is lower than other'.format(self.__class__.__name__)
print Com(1) == Com(2)
好,现在我们实现一个比较有意思的:
现在有一道题:
a = ?, a<a is True
即a应该等于什么呢,才能是a<a成立?
Python内置的数据结构肯定是实现不聊了,这时就可以用到运算符__lt__了:
class A(object):
def __lt__(self, other):
return True
a = A()
print a<a
3、__repr__和__str__
除了上面的属性运算符,这两个也是最常见的。他们是以表达式的形式来表示类。他们的共同特点是必须都要返回字符串。不同点是当我们执行print操作时,它会首先尝试__str__和str函数,也就是说如果__str和__repr__都定义了,那么print操作也只是调用__str__,看个例子:
class B(object):
def __repr__(self):
return 'B'
def __str__(self):
return 'I am B'
b = B()
print b
I am B
而__repr__用途就更广泛啦,用户交互模式下提示回应以及repr函数。此外,如果没有定义__str__,那执行print操作时,就会调用__repr__,但反过来却不行,即如果你在交互模式下敲,如果没定义__repr__,是不会调用__str__的。
因此,__repr__这种方式最常用啦。
微信分享/微信扫码阅读