python魔术方法

在Python中,被双下滑线包围起来的方法(定义在类中)叫魔术方法(Magic Method),比如我们最常见的init()就是一个典型的魔术方法。

一、构造和初始化

newinit相配合才是python中的类构造器。

1
2
3
4
5
6
7
8
9
10
11
12
class A:
pass

class B(A):
def __new__(cls): # 传入类(cls)
print("__new__方法被执行")
return super().__new__(cls)

def __init__(self): # 传入类的实例化对象(self)
print("__init__方法被执行")

b = B()

二、类的描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class A:
'''我是一个测试类'''
def __init__(self, item):
self.item = item

def __repr__(self): # 类对象打印格式
return "something:"+str(self.item)

a = A(100)

print('这是哪个类:')
print(a.__class__)
print('这个类是做什么的:')
print(a.__doc__)
print('打印这个类:')
print(a)

三、类的属性访问控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class A:
def __init__(self, age):
self.age = age

def __getattribute__(self, key): # 访问已存在的属性时调用
return super().__getattribute__(key)

def __getattr__(self, key): # 访问不存在的属性时调用
return '属性不存在!'

def __setattr__(self, key, value): # 设置实例对象的一个新的属性时调用
self.__dict__[key] = value

def __delattr__(self, key): # 删除一个实例对象的属性时调用
print("对象被销毁.")

a = A(15)

print('查询属性值:')
print(a.age)
print(a.name)
print('属性赋值:')
a.age = 16
print(a.age)
print('属性删除:')
a.qq = "123"
del a.qq

四、描述器类的魔术方法

描述器是通过获取、设置以及删除的时候被访问的类。从描述器的创建来说,一个类中定义了getsetdelete中的一个或几个,这个类的实例就可以叫做一个描述器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 创建一个描述器的类, 它的实例就是一个描述器
# 这个类要有__get__、__set__这样的方法
# 这种类是当做工具使用的, 不单独使用
class M:
def __init__(self, x=1):
self.x = x

def __get__(self, instance, owner):
return self.x

def __set__(self, instance, value):
self.x = value

# 调用描述器的类
class A:
m = M() # m就是一个描述器

a = A()
print(a.m) # 1
a.m = 2
print(a.m) # 2

下面再看一个单位转换的描述器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Meter(object):
def __init__(self, value=0.0):
self.value = float(value)

def __get__(self, instance, owner):
return self.value

def __set__(self, instance, value):
self.value = float(value)

class Foot(object):
def __get__(self, instance, owner):
return instance.meter * 3.2808

def __set__(self, instance, value):
instance.meter = float(value) / 3.2808

# 调用描述器的类
class Distance(object):
meter = Meter() # 单位'米'的描述器
foot = Foot() # 单位'英尺'的描述器

d = Distance()
d.foot = 30
print(d.foot)
print(d.meter)
d.meter = 10
print(d.meter)
print(d.foot)

更多

五、容器类的魔术方法

我们常用的list、dict、tuple、string等等就是容器类。python的容器类型分为可变类型(如list、dict)和不可变类型(如string、tuple),可变容器和不可变容器的区别在于,不可变容器一旦赋值后,不可对其中的某个元素进行修改。

注意事项

  • 要实现不可变容器的话,你只能定义 lengetitem
  • 可变容器协议需要所有不可变容器的所有,另外还需要 setitemdelitem
  • 如果你希望你的对象是可迭代的话,你需要定义 iter 返回一个迭代器。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
class FunctionalList: 
'''实现了内置类型list的功能,并丰富了一些其他方法'''
def __init__(self, values=None):
if values is None:
self.values = []
else:
self.values = values

def __len__(self):
# 序列长度
return len(self.values)

def __getitem__(self, key):
# 获取某位元素
return self.values[key]

def __setitem__(self, key, value):
# 修改某位元素
self.values[key] = value

def __delitem__(self, key):
# 删除某位的元素
del self.values[key]

def __iter__(self):
# 迭代
return iter(self.values)

def __reversed__(self):
# 反转序列
return FunctionalList(reversed(self.values))

def append(self, value):
# 在尾部添加元素
self.values.append(value)

def head(self):
# 获取第一个元素
return self.values[0]

def last(self):
# 获取最后一个元素
return self.values[-1]

def drop(self, n):
# 获取所有元素,除了前N个
return self.values[n:]

def take(self, n):
# 获取前N个元素
return self.values[:n]

l = FunctionalList([1,2,3,4,5,6])
print(l.take(5))
print(list(l.__iter__()))
print(list(l.__reversed__()))
l.__delitem__(3)
print(list(l.__iter__()))
l[3] = 9 # 触发__setitem__
print(list(l.__iter__()))