python进阶——类(四)常用内置方法
本文最后更新于:1 年前
¶(七)常用内置方法
¶1. 简介:
这里介绍的常用内置方法主要是对类的一些相关用法的补充,便于解决创建类遇到的一些常见问题,同时对其进行简单演示来表示其具体的应用场景。
__init__方法不再介绍,前面的使用和介绍已经非常详细了。
-
__str__()和__repr__():
这两个方法的目的使为了显式的显示对象的必要信息,方便查看和调试。
__str__()被print默认调用,控制用户的展示;而__repr__被控制台输出默认调用,控制调试的展示。
-
__str__用于表示对象代表的含义,返回一个字符串,可以根据需要返回一个实例转化成字符串之后的结果。
具体用法如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class exmp:
def __init__(self):
self.x=1
self.y=2
def __str__(self):
return f'{self.__class__}:x={self.x},y={self.y}'
class exmp2:
def __init__(self):
self.x=1
self.y=2
e=exmp()
e2=exmp2()
print(e)
print(e2)
# 运行结果:
# <class '__main__.exmp'>:x=1,y=2
# <__main__.exmp2 object at 0x0000017336228210>能够看出输出实例时的内容发生了改变。
-
__repr__的用途和用法都与__str__类似,所以一般直接使用__repr__= __str__将其返回字符串复制给__repr__
如果为使用者和开发者提供的信息不一致,再单独定义__repr__即可。
简单例子如下()此为控制台的输入和输出。
1
2
3
4
5
6
7
8
9
10
11
12
13class exmp3:
def __init__(self):
self.x=1
self.y=2
def __str__(self):
return f'{self.__class__}:x={self.x},y={self.y}'
def __repr__(self):
return f'{self.__class__}:x={self.x},y={self.y}'+'——repr'
e=exmp3()
e
<class '__main__.exmp3'>:x=1,y=2——repr
-
-
__call__():
不管是内置函数还是自定以函数,函数实际上是实现了__call__方法的对象,这是可调用对象的一种——调用函数时,"名称()"实际上等价于"名称.__call__()"的写法。
其他的可调用对象还包括Python的实例对象和实例方法。
__call__方法除了函数以外,也可以给实例对象提供被执行的能力,也就是将实例对象转变为一个可调用对象,其实际功能效果类似于在类中重载了()运算符,使得类的实例对象可以以"对象名()"的形式使用。
实现了__call__方法的类实例,可以传入参数也可以返回值。
具体例子如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22class exmp:
def __init__(self,a):
self.a=a
def __call__(self,b):
print("a=",self.a)
print("b=",b)
print("a+b=",self.a+b)
return self.a+b
e=exmp(10)
result=e(20)
print(result)
def fun(i):
print("fun",i)
fun(10)
fun.__call__(20)
# 运行结果:
# a= 10
# b= 20
# a+b= 30
# 30
# fun 10
# fun 20 -
__iter__()和__next__():
这两个方法的具体内容在python进阶——高级特性(二)迭代、迭代器 - ZZHの个人博客 (07xiaohei.com)种已经进行了详细的介绍,这里只进行简要介绍。
这两个方法用于将一个对象模拟成序列,内部类型如列表、元组等都可以迭代,重写这两个方法就可以实现自定义的迭代对象。 __iter__方法向系统说明了这是一个可迭代对象,__next__方法向系统说明了该可迭代对象的迭代算法。
__iter__方法需要返回self,__next__方法需要返回对应的元素。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25class Myfib:
def __iter__(self):
self.i1=0
self.i2=1
return self
def __next__(self):
result=self.i1+self.i2
self.i1=self.i2
self.i2=result
return result
use_fib=Myfib()
j = 1
for i in use_fib:
if i<100000:
print(i,end=" ")
j+=1
else:
break
if j==10:
print()
j=1
# 运行结果:
# 1 2 3 5 8 13 21 34 55
# 89 144 233 377 610 987 1597 2584 4181
# 6765 10946 17711 28657 46368 75025再举一个例子,写一个首项为10,公差为5的等差数列:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Mysequence:
def __iter__(self):
self.i=10
return self
def __next__(self):
self.i+=5
return self.i
se=Mysequence()
for i in se:
if i<=100:
print(i,end=" ")
else:
break
# 运行结果:
# 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 -
__getitem__(),__setitem__(),__delitem__():
__getitem__()方法把类中的属性定义为序列或者字典,并且可以用此方法输出其中的某个元素,其效果类似于重载[]运算符给类,可以通过"实例名[索引]/[切片]"的方式来访问实例对象的某个元素。
对于传入的是索引还是切片,可以通过isinstance函数判断。
判断是索引,使用ininstance(item,int)判断item是否为int类型,确定其是否为数字索引;使用ininstance(item,slice)判断其是否为切片;使用ininstance(item,str)等判断其是否为key。
具体的例子如下:
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
41class mynumlist:
def __init__(self):
self.list_use=[]
def __iter__(self):
self.i=10
self.list_use.append(self.i)
return self
def __next__(self):
self.i+=5
self.list_use.append(self.i)
return self.i
def __getitem__(self, item):
if isinstance(item,int):
return self.list_use[item]
elif isinstance(item,slice):
start=item.start
stop=item.stop
return self.list_use[start:stop]
else:
return "error"
mn=mynumlist()
y=0
for i in mn:
if y!=30:
y+=1
print(i,end=" ")
else:
break
print()
print(mn[10])
print(mn[:])
print(mn[2:10])
print(mn[-8:-2])
print(mn["1"])
# 运行结果:
# 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 105 110 115 120 125 130 135 140 145 150 155 160
# 60
# [10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165]
# [20, 25, 30, 35, 40, 45, 50, 55]
# [130, 135, 140, 145, 150, 155]
# error除了上面的列表,还可以是字典:
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
37class mydic:
def __init__(self):
self.dirc_use={}
self.index=1
def __iter__(self):
self.i=10
self.dirc_use[str(self.index)]=self.i
return self
def __next__(self):
self.index+=1
self.i+=5
self.dirc_use[str(self.index)] = self.i
return self.i
def __getitem__(self, item):
if isinstance(item,str):
return self.dirc_use.get(item)
else:
return "error"
md=mydic()
y=0
for i in md:
if y!=30:
y+=1
print(i,end=" ")
else:
break
print()
print(md["1"])
print(md["10"])
print(md[8])
print(md["1000"])
# 运行结果:
# 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 105 110 115 120 125 130 135 140 145 150 155 160
# 10
# 55
# error
# None可以自行定义更具体的判断条件和处理方法。
__setitem__方法则是对上面某个使用索引内值的修改,可以让类按照一定的方法存储和映射key对应的value,该方法的赋值是通过类实例名直接完成的。
具体例子如下:
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
41class mynumlist:
def __init__(self):
self.list_use=[]
def __iter__(self):
self.i=10
self.list_use.append(self.i)
return self
def __next__(self):
self.i+=5
self.list_use.append(self.i)
return self.i
def __getitem__(self, item):
if isinstance(item,int):
return self.list_use[item]
elif isinstance(item,slice):
start=item.start
stop=item.stop
return self.list_use[start:stop]
else:
return "error"
def __setitem__(self, key, value):
if isinstance(key, int):
self.list_use[key]=value
else:
return "error"
mn=mynumlist()
y=0
for i in mn:
if y!=30:
y+=1
print(i,end=" ")
else:
break
print()
print(mn[10])
mn[10]=114514
print(mn[8:11])
# 运行结果:
# 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 105 110 115 120 125 130 135 140 145 150 155 160
# 60
# [50, 55, 114514]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
43class mydic:
def __init__(self):
self.dirc_use={}
self.index=1
def __iter__(self):
self.i=10
self.dirc_use[str(self.index)]=self.i
return self
def __next__(self):
self.index+=1
self.i+=5
self.dirc_use[str(self.index)] = self.i
return self.i
def __getitem__(self, item):
if isinstance(item,str):
return self.dirc_use.get(item)
else:
return "error"
def __setitem__(self, key, value):
if isinstance(key,str):
self.dirc_use[key]=value
else:
print("error")
md=mydic()
y=0
for i in md:
if y!=30:
y+=1
print(i,end=" ")
else:
break
print()
print(md["1"])
print(md[8])
print(md["1000"])
md["3"]="123456789"
print(md["3"])
# 运行结果:
# 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 105 110 115 120 125 130 135 140 145 150 155 160
# 10
# error
# None
# 123456789__delitem__方法在对对象的组成部分使用__del__语句的时候被调用,需删除与key相关联的值。
举例如下:
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
49class mynumlist:
def __init__(self):
self.list_use=[]
def __iter__(self):
self.i=10
self.list_use.append(self.i)
return self
def __next__(self):
self.i+=5
self.list_use.append(self.i)
return self.i
def __getitem__(self, item):
if isinstance(item,int):
return self.list_use[item]
elif isinstance(item,slice):
start=item.start
stop=item.stop
return self.list_use[start:stop]
else:
return "error"
def __setitem__(self, key, value):
if isinstance(key, int):
self.list_use[key]=value
else:
print("error")
def __delitem__(self, key):
if isinstance(key, int):
del self.list_use[key]
else:
print("error")
mn=mynumlist()
y=0
for i in mn:
if y!=30:
y+=1
print(i,end=" ")
else:
break
print()
print(mn[10])
mn[10]=114514
print(mn[8:11])
del mn[10]
print(mn[8:11])
# 运行结果:
# 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 105 110 115 120 125 130 135 140 145 150 155 160
# 60
# [50, 55, 114514]
# [50, 55, 65]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
51class mydic:
def __init__(self):
self.dirc_use={}
self.index=1
def __iter__(self):
self.i=10
self.dirc_use[str(self.index)]=self.i
return self
def __next__(self):
self.index+=1
self.i+=5
self.dirc_use[str(self.index)] = self.i
return self.i
def __getitem__(self, item):
if isinstance(item,str):
return self.dirc_use.get(item)
else:
return "error"
def __setitem__(self, key, value):
if isinstance(key,str):
self.dirc_use[key]=value
else:
print("error")
def __delitem__(self, key):
if isinstance(key, str):
del self.dirc_use[key]
else:
print("error")
md=mydic()
y=0
for i in md:
if y!=30:
y+=1
print(i,end=" ")
else:
break
print()
print(md["1"])
print(md[8])
print(md["1000"])
md["3"]="123456789"
print(md["3"])
del md["3"]
print(md["3"])
# 运行结果:
# 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 105 110 115 120 125 130 135 140 145 150 155 160
# 10
# error
# None
# 123456789
# None -
__slots__:
__slots__是一个类属性,可以赋值为字符串、可迭代对象或由实例使用的变量名构成的字符串序列。
__slots__允许显式声明数据成员,为已声明的变量保留空间,限制能够添加的属性名(也就是禁止为每个实例创建__dict__和__weakref__)。
通过阻止每个实例创建自己的__dict__而使用__slots__,在大量创建实例时,可以显著地节省内存空间并提升属性的查找速度。
——本质上,__dict__是哈希表结构,动态占用内存,开销大,而__slots__能够在编译时期使解释器确定属性,分配固定的空间存储已知的属性。
__slots__仅对当前类实例起作用,不会对继承的派生类起作用,需要派生类定义自己的__slots__。
例子如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class test:
__slots__ = ("a","b","c")
def __init__(self):
self.a=1
self.b=2
self.c=3
self.d=10
t=test()
# 运行结果:
# Traceback (most recent call last):
# File "D:\pycharmwork\blog_use.py", line 3587, in <module>
# t=test()
# ^^^^^^
# File "D:\pycharmwork\blog_use.py", line 3586, in __init__
# self.d=10
# ^^^^^^
# AttributeError: 'test' object has no attribute 'd'可以看到,只有abc的属性名可以使用,其他的属性名使用均错误。
-
__getattr__(),__setattr__(),__delattr__():
__getattr__方法用于处理访问不存在属性的方法,可以输出相关的异常信息。
__setattr__方法用于设置属性值的时候,每设置一次属性的值都要进入一次该方法,注意该方法不要递归调用,也不要在该方法种再次直接设置属性值,否则可能会造成死循环。
__delattr__方法用于删除属性值的时候,也要注意避开死循环。
使用的举例如下:
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
40class test:
def __init__(self):
self.i=1
def __getattr__(self, item):
print("Don't get!")
return False
def __setattr__(self, key, value):
print("Setting...")
self.__dict__[key]=value
print("Finish!")
def __delattr__(self, item):
print("Deling...")
if self.__dict__.get(item):
del self.__dict__[item]
print("Successful!")
else:
print("Failed!")
t=test()
t.i=5
print(t.i)
t.j=10
print(t.j)
print(t.z)
del t.i
del t.z
# 运行结果:
# Setting...
# Finish!
# Setting...
# Finish!
# 5
# Setting...
# Finish!
# 10
# Don't get!
# False
# Deling...
# Successful!
# Deling...
# Failed!