05 特殊方法

非运算类

  • 字符串、字节表示

    __repr__, __str__, __format__, __bytes__

  • 转换为数字

    __abs__, __bool__, __complex__, __int__, __float__, __hash__, __index__

  • 模拟集合

    __len__, __getitem__, __setitem__, __delitem__, __contains__

  • 迭代

    __iter__, __reversed__, __next__

  • 可调用

    __call__

  • 环境管理

    __enter__, __exit__

  • 创建、销毁实例

    __new__, __init__, __del__

  • 属性管理

    __getattr__, __getattribute__, __setattr__, __delattr__, __dir__

  • 属性描述

    __get__, __set__, __delete__

  • 类功能

    __prepare__, __instancecheck__, __subclasscheck__

5.1 构造、初始化和删除

  • __new__ 用来创建类并返回这个类的实例。注意如果不返回实例的话,相当于实例没有被创建出来。注意这是一个静态方法,且不需要专门用static来声明,也就是说这时一个特例。

  • __init__ 用来初始化

  • __del__ 相当于析构函数

class MyClass:
def __new__(cls):
print('in new')
return super().__new__(cls)
def __init__(self):
print('in init')
def __del__(self):
print('in del')
c = MyClass()

上面的代码执行后会输出 s

in new
in init
in del

5.2 控制属性访问

  • __getattr__(self, name) 定义当用户试图获取一个不存在的属性时的行为。参数name就是使用时不存在的属性的名字。

  • __setattr__(self, name, value) 无论属性是否存在,它都允许你定义对对属性的赋值行为,以为这你可以对属性的值进行个性定制。实现setattr时要避免"无限递归"的错误。

# 错误的用法,这样会无限递归
def __setattr__(self, name, value):
self.name = value
# 正确用法
def __setattr__(self, name, value):
self.__dict__[name] = value # 给类中的属性名分配值
# 定制特有属性
  • __delattr__(self, name) 与setattr相反,删除一个属性。也要注意无限递归的错误。

class MyClass:
def __getattr__(self, name):
print('get not existed attr {}'.format(name))
def __setattr__(self, name, value):
print('set attr {} = {}'.format(name, value))
self.__dict__[name] = value
def __delattr__(self, name):
print('del {}'.format(name))
del self.__dict__[name]
if __name__ == '__main__':
c = MyClass()
c.age = 1
del c.age
c.age
  • __getattribute__(self, name) 定义了你的属性被访问时的行为,相比较,getattr只有该属性不存在时才会起作用。调用getattr前必定会调用 getattributegetattribute同样要避免"无限递归"的错误。需要提醒的是,最好不要尝试去实现getattribute,因为很少见到这种做法

5.3 容器

  • __len__(self) 返回容器的长度,可变和不可变类型都需要实现。

  • __getitem__(self, key) 定义对容器中某一项使用 self[key] 的方式进行读取操作时的行为。这也是可变和不可变容器类型都需要实现的一个方法。它应该在键的类型错误式产生 TypeError 异常,同时在没有与键值相匹配的内容时产生 KeyError 异常。

  • __setitem__(self, key) 定义对容器中某一项使用 self[key] 的方式进行赋值操作时的行为。它是可变容器类型必须实现的一个方法,同样应该在合适的时候产生 KeyError 和 TypeError 异常。

  • __delitem__(self, key) del self[key]使用索引删除某个对象

  • __iter__(self, key) 它应该返回当前容器的一个迭代器。迭代器以一连串内容的形式返回,最常见的是使用 iter() 函数调用,以及在类似 for x in container: 的循环中被调用。迭代器是他们自己的对象,需要定义iter方法并在其中返回自己。

  • __reversed__(self) 定义了对容器使用 reversed() 内建函数时的行为。它应该返回一个反转之后的序列。当你的序列类是有序时,类似列表和元组,再实现这个方法,

  • __contains__(self, item) contains定义了使用 in 和 not in 进行成员测试时类的行为。你可能好奇为什么这个方法不是序列协议的一部分,原因是,如果 contains没有定义,Python就会迭代整个序列,如果找到了需要的一项就返回 True 。

  • __missing__(self ,key) missing 在字典的子类中使用,它定义了当试图访问一个字典中不存在的键时的行为(目前为止是指字典的实例,例如我有一个字典 d , “george” 不是字典中的一个键,当试图访问 d[“george’] 时就会调用 d.missing(“george”) )。

5.4 可调用对象

call可以将类作为像函数调用

class Fib(object):
def __call__(self, num):
a, b, fib_list = 0, 1, []
for i in range(num):
fib_list.append(a)
a, b = b, a + b
return fib_list
if __name__ == '__main__':
f = Fib()
print(f(20))

输出

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]

5.5 slots限制当前类能拥有的属性

class MyClass:
__slots__ = ('dd')
if __name__ == '__main__':
c = MyClass()
c.dd = 1
c.zz = 2

会报错

Traceback (most recent call last):
File "test.py", line 9, in <module>
c.zz = 2
AttributeError: 'MyClass' object has no attribute 'zz'