目录
一、对魔术方法的理解
魔术方法Python的一种高级语法,实质也是一种内置方法,调用类实例化的对象的方法时自动调用魔法函数
形式为__XX__,不可自定义,但可重写
存在的目的是为了给python的解释器进行调用,几乎每个魔法方法都有一个对应的内置函数,或者运算符,当我们对这个对象使用这些函数或者运算符时就会调用类中的对应魔法方法,可以为你写的类增加一些额外功能
二、魔术方法分类
- 创建、初始化与销毁 __init__与__del__
- hash
- bool
- 可视化
- 运算符重载容器和大小
- 可调用对象
- 上下文管理
- 反射
- 描述器
- 其他杂项
三、基本魔术方法
1. __init__ 构造函数
当一个实例被创建的时候初始化的方法。不写默认为pass
必须包含self参数,且必须为第一个参数,习惯性命名为self,self指的是实例本身,不需要传参
class A:
def __init__(self, name, age):
self.a = 'a'
self.name = name
self.age = age
2. __del__ 析构函数
功能和 __init__() 相反,其用来销毁实例化对象
如果之前创建的类实例化对象后续不再使用,可以手动将其销毁,释放其占用的内存空间,销毁的过程中会调用__del__方法
class A:
def __init__(self):
self.a = 'a'
def __del__(self):
print("----del 实例-----")
test = A()
del test
3. __hash__
内建函数 hash()调用的返回值,返回一个整数。如果定义这个方法该类的实例就可hash。
class A:
def _init_(self, name, age=18):
self.name = name
def _hash_(self):
return 1
def _repr_(self):
return self.name
4. __eq__
对应==操作符,判断2个对象是否相等,返回bool值
__hash__方法只是返回一个hash值作为set的key,但是去重还需要_eq__来判断2个对象是否相等
hash值相等,只是hash冲突,不能说明两个对象是相等的。
因此,一般来说提供_hash__方法是为了作为set或者dict的key,所以 去重需要同时提供_eq_方法。
不可hash对象isinstance(p1,collections.Hashable)一定为False。
from collections import Hashable
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __hash__(self):
return hash((self.x, self.y))
def __eq__(self, other):
return self.x == other.x and self.y == other.y
p1 = Point(4,5)
p2 = Point(4,5)
print(hash(p1))
print(hash(p2))
print(p1 is p2)
print(p1 == p2)
print(isinstance(p1, Hashable))
5. __bool__
内建函数bool(),或者对象放在逻辑表达式的位置,调用这个函数返回布尔值。
没有定义__bool__(),就找__len__()返回长度,非0位真。如果__len__()也没有定义,那么所有实例都返回真
class A: pass
print(bool(A()))
if A():
print("real A")
class B:
def __bool__(self):
return False
print(bool(B))
print(bool(B()))
if B():
print("real B")
class C:
def __len__(self):
return 0
print(bool(C()))
if C():
print("real C")
可视化
6. __repr__
内建函数repr()对一个对象获取字符串表达。
调用__repr__方法返回字符串表达,如果_repr__也没有定义,就直接返回object的定义就是显示内存地址信息
7. __str__
str()函数、内建函数format()、print()函数调用,需要返回对象的字符串表达。
如果没有定义,就去调用__repr__ 方法返回字符串表达,如果__repr__没有定义,就直接返回对象的内存地址信息
8. __bytes__
bytes()函数调用,返回一个对象的bytes表达,即返回bytes对象
class A:
def __init__(self, name, age=18):
self.name = name
self.age = age
def __repr__(self):
return 'repr: {} {}' .format(self.name, self.age)
def __str__(self):
return 'str:{} {}'.format(self.name, self.age)
def __bytes__(self):
#return "{} is }".format(self.name,self.age).encode()
import json
return json.dumps(self.__dict__).encode()
print(A('tom')) #print 函数使用__str__
print([A('tom')]) #[] 使用__str__,但其内部使用__repr__
print(([str(A('tom'))]))
s='1'
print(s)
print(['a'],(s,))
print(bytes(A('tom')))
9. 运算符重载
class A:
def __init__(self, name, age=18):
self.name = name
self.age = age
def __sub__(self, other):
return self.age - other.age
def __isub__(self,other):
return A(self.name, self - other)
tom = A('tom')
jerry = A('jerry', 16)
print(tom - jerry)
print(jerry - tom, jerry.__sub__(tom))
print(id(tom))
tom -= jerry
print(tom.age, id(tom))
容器相关方法
10. __len__
- 内建函数len(),返回对象的长度(>=0的整数)
- 如果把对象当做容器类型看,就如同list或者dict。
- bool()函数调用的时候,如果没有__bool__()方法,则会看 __len__()方法是否存在,存在返回非0为真
11. __iter__
- 迭代容器时,调用,返回一个新的迭代器对象
12. __contains__
- in 成员运算符,没有实现,就调用__iter__ 方法遍历
13. __getitem__
- 实现self[key]访问。
- 序列对象,key接受整数为索引,或者切片。
- 对于set和dict,key为hashable。
- key不存在引发KeyError异常
14. __setitem__
- 和__getitem__的访问类似,是设置值的方法
15. __missing__
- 字典或其子类使用__getitem__()调用时,key不存在执行该方法
class Cart:
def __init__(self):
self.items = []
def __len__(self):
return len(self.items)
def additem(self, item):
self.items.append(item)
def __iter__(self):
return iter(self.items)
def __getitem__(self, index):
return self.items[index]
def __setitem__(self, key, value):
self.items[key] = value
def __str__(self):
return str(self.items)
def __add__(self, other):
self.items.append(other)
return self
cart = Cart()
cart.additem(1)
cart.additem('abc')
cart.additem(13)
print(len(cart))
print(bool(cart))
for i in cart:
print(i)
print(1 in cart)
print(122 in cart)
print(cart[1])
cart[1] = 'xyzzzzz'
print(cart)
可调用对象:
定义一个类,并实例化得到其实例,将实例像函数一样调用
函数即对象,对象加上(),就是调用对象的__call__()方法,例如foo()
16. __call__
类中定义一个该方法,实例就可以像函数一样调用
class Adder:
def __call__(self, *args):
ret = 0
for x in args:
ret += x
self.ret = ret
return ret
adder = Adder()
print(adder(4, 5, 6))
print(adder.ret)