1. __str__ 和 __repr__
- 用于 对象的终端输出。
class test(object): def __init__(self): self.a = 100 def __str__(self): return '我是__str__属性a的值为:%s' % self.a def __repr__(self): return '我是__repr__属性a的值为:%s' % self.a t = test() #print(t) # 优先调用__str__,__str__没有定义,会去调用__repr__ print(str(t)) # 调用 __str__,__str__没有定义,会去调用__repr__ print(repr(t)) # 调用 __repr__ # __str__()用于显示给用户,而__repr__()用于显示给开发人员
2. __cmp__
此方法用于 自定义 两个对象的 比较行为
这个方法 在python3中已经被删除了。我们来学习下 在python2中如何使用。
-
首要 学习下 cmp() 这个內建函数。
In [7]: cmp(10,5) Out[7]: 1 In [8]: cmp(5,10) Out[8]: -1 In [9]: cmp(5,5) Out[9]: 0cmp()函数, 接收两个参数。有如下的特点:
如果返回值为 1, 代表 第一个参数 大于 第二个参数。
如果返回值为-1,代表 第一个参数 小于 第二个参数。
如果返回值为 0, 代表 第一个参数 等于 第二个参数。 -
抛出问题: 如果 有两个 字符串 ,我们需要比较字符串的 长度。使用cmp()函数如何达到我们的目的呢?
class Word(str): def __cmp__(self, other): if len(self) > len(other): return 1 elif len(self) < len(other): return -1 elif len(self) == len(other): print('----比较结果相等------') return 0 w1 = Word('asda') w2 = Word('abcd') print(w1==w2) print(cmp(w1,w2)) # cmp函数的 两个参数都是 Word类型的时候,才会调用__cmp__方法运行代码:打印了False和0.为什么第一个print没有打印True呢?而cmp()函数比较的结果是相等。
这是因为 cmp() 函数在比较的时候 调用了 __cmp__ 方法,而 == 这个比较操作符,没有调用__cmp__ 方法。
如果使用 == 比较 如何达到相同的效果呢?后面会介绍。
注意:__cmp__ 这个方法 应该在 self > other 返回 正整数。self < other 返回负整数。self == other 返回 0. 一定要严格遵守这条约定。
3. __eq__ 、__ne__ 、__lt__ 、__gt__、__le__、__ge__
- python2 中 __cmp__ 的替换方案.
__eq__ : 定义 比较操作符 == 的行为
__ne__ : 定义 比较操作符 != 的行为
__lt__ : 定义 比较操作符 < 的行为
__gt__ : 定义 比较操作符 > 的行为
__le__ : 定义 比较操作符 <= 的行为
__ge__ : 定义 比较操作符 >= 的行为 - 下面 以 __eq__ 为例:如果想 通过 == 来比较 两个 字符串的长度,应该如何做呢?
注意:这里,只有 Word类 创建出来的 字符串对象,在进行 == 比较时,才会 通过 比较字符串的长度 得出比较结果。比如:'abc'=='def' 这样直接比较,还是用的python默认的方式进行比较的。其他的方法和 __eq__ 的用法 是一样的。class Word(str): def __eq__(self, other): return len(self) == len(other) w1 = Word('abc') w2 = Word('jkl') print(w1==w2) # w1.__eq__(w2) print(w1)
4. __getattr__
- 当用户试图访问一个根本不存在(或者暂时不存在)的属性时,你可以通过这个魔法方法来定义类的行为。这个可以用于捕捉错误的拼写并且给出指引,使用废弃属性时给出警告(如果你愿意,仍然可以计算并且返回该属性),以及灵活地处理AttributeError。只有当试图访问不存在的属性时它才会被调用。
class Person(object): def __init__(self, name): self.name = name def __getattr__(self,name): return '%s is not exist' % name a = Person('xiao') print(a.age) # 终端输出:age is not exist
5. __getattribute__
class Animal(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __getattribute__(self, obj):
if obj == 'name':
print('-----记录日志name-------')
return object.__getattribute__(self, obj)
elif obj == 'age':
print('-----记录日志age--------')
return '禁止访问'
elif obj == 'test':
return object.__getattribute__(self, obj)
elif obj == '__dict__':
return '不允许访问!'
def test(self):
print("--test--")
a = Animal('xiao', 19)
print(a.name)
print(a.age)
a.test()
print(a.__dict__)
print(a.haha)
终端依次输出:
-----记录日志name-------
xiao
-----记录日志age--------
禁止访问
--test--
不允许访问!
None
print(a.name) 执行过程:
python解释器检测到 实例对象a需要访问name属性 ,
刚好,这个类重写了__getattribute__方法,
那么,程序就直接去执行__getattribute__方法,
执行完毕后,把__getattribute__方法的返回值,赋值给a.name,
最后执行print(a.name)
obj的值就是'name'这个字符串。
注意:实例对象 调用这个类的方法的时候(所有方法),也会调用 __getattribute__ 方法。
属性不存在也会触发这个 方法。
6. __setattr__
- 它允许你自定义某个属性的赋值行为,不管这个属性存在与否,也就是说你可以对任意属性的任何变化都定义自己的规则。
- 当给实例属性赋值的时候,这个方法会被调用。如果你在 __setattr__ 方法里面去给属性赋值,会导致无限递归。
当创建实例对象a的 时候,执行__init__方法,给实例属性age赋值,(注意:执行到这里并没有给age属性赋值),然后调用 __setattr__ 方法。继续执行 print(a.age) 语句,程序会抛出 AttributeError 这个异常,因为还没有给 name 属性 赋值。应该怎么做呢?class Person(object): def __init__(self, age): self.age = age def __setattr__(self,name,value): print('%s is not exist' % name) a = Person(18) print(a.age)
在 __setattr__ 方法里 调用下 父类的 __setattr__ 的方法就行了。( object.__setattr__(self, name, value) )
7. __delattr__
- 这个魔法方法和 __setattr__ 几乎相同,只不过它是用于处理删除属性时的行为。和 __setattr__ 一样,使用它时也需要多加小心,防止产生无限递归.(在 __delattr__ 的实现中调用 del self.name 会导致无限递归)。
当代码执行到 del a.name 时(此时,并没有执行 del a.name ),会调用 __delattr__ 方法,如果想让程序继续执行 del a.name 那么需要在 __delattr__ 方法中 调用父类的方法class Person(object): def __init__(self, name): self.name = name def __delattr__(self, name): print('-------删除属性--------') a = Person('xiao') print(a.name) del a.name print(a.name)
8. __reversed__
- 用于反向迭代
reversed(s), 相当于 s.__reversed__().class test(object): def __init__(self, b): # 5 [0,1,2,3,4] self.b = b def __iter__(self): self.a = 0 return self def __next__(self): if self.a < self.b: i = self.a self.a += 1 return i else: raise StopIteration def __reversed__(self): print('hahah') return sorted(self, reverse=True) it = test(10) print(list(it)) print(list(reversed(it)))
__reversed__ 方法 要求返回一个 迭代器。
s 这个对象,需要实现 __reversed__ 方法。如果没有实现 __reversed__ 方法,reversed(s) 会把 s 这个对象当成一个序列处理,如果s不是序列,就会抛出类型错误异常。
9. __len__
- 返回 容器的长度
len(t) ,实际上 调用了 t 的__len__ 方法。class test(object): def __init__(self): self.li = [1, 2, 3] def __len__(self): print('test') return len(self.li) t = test() print(len(t))
10. __contains__
- 定义 对象 通过 in 或者 not in 测试成员时的行为。
class test(object): def __contains__(self,item): print('item is {}'.format(item)) return True t = test() print(1 in t) print(1 not in t)
11. __getitem__
- 适用于 序列和字典 这些对象 (列表,元祖,字符串等等)
- 定义 对象 通过 self[key] 访问时的行为。
class Seq(object): def __getitem__(self, i): print("__getslice__") print(i) return 100 obj = Seq() print(obj[1:2]) print("--------------------") print(obj["abc"]) 依次输出: __getslice__ slice(1, 2, None) 100 -------------------- __getslice__ abc 100
12. __setitem__
- 定义 对象 通过 self[key] = value 赋值时的行为。
class Seq(list): def __setitem__(self, i, value): print("__getslice__") print(i) print(value) super().__setitem__(i, value) obj = Seq() obj[0:2] = [1, 2] # 设置的值 必须是 可迭代对象 print(obj[0:2]) print("--------------------") 输出: __getslice__ slice(0, 2, None) [1, 2] [1, 2] --------------------
13. __delitem__
- 定义 对象 通过 del self[key] 删除时的行为。
class test(object): def __delitem__(self, key): print('key is {}'.format(key)) t = test() del t[1] print('--------分割线-----------') del t['name']