前言
最近在学习python,学习到了一个之前没接触过的--特殊方法。
什么是特殊方法?当我们在设计一个类的时候,python中有一个用于初始化的方法$__init__$,类似于java中的构造器,这个就是特殊方法,也叫作魔术方法。简单来说,特殊方法可以给你设计的类加上一些神奇的特性,比如可以进行python原生的切片操作,迭代、连乘操作等。在python中,特殊方法以双下划线开始,以双下划线结束。
一个大例子
数学中有一个表示数的概念叫做向量,但是python中的数据类型却没有。我们来设法用python实现它。
首先考虑,向量跟普通的数据类型不同,传统的数可以直接进行运算,向量则需要对不同的坐标分别运算。来试试。
首先定义一个类,实现初始化方法。
1
2
3
4
5
6
|
# 实现向量类型 class Vector: def __init__( self , x = 0 , y = 0 ): self .x = x self .y = y |
如何实现向量的加法?二维向量中,向量的加法就是每个坐标分别相加得到的结果。在python中有个$__add__$方法,用来进行加法操作。
1
2
3
4
5
6
7
8
9
10
11
|
class Vector: def __init__( self , x = 0 , y = 0 ): self .x = x self .y = y # 实现向量加法 def __add__( self , other): x = self .x + other.x y = self .y + other.y return Vector(x, y) |
我们对x和y变量分别进行相加,然后返回Vector。在python你可以对字符串直接用加法拼接起来的原理就在此,python实现了针对字符串的add方法。
实现了加法,乘法的道理一样,分别对每个坐标单独相乘即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class Vector: def __init__( self , x = 0 , y = 0 ): self .x = x self .y = y # 实现向量加法 def __add__( self , other): x = self .x + other.x y = self .y + other.y return Vector(x, y) # 实现向量乘法,例如r*3 def __mul__( self , scalar): return Vector( self .x * scalar, self .y * scalar) |
我们在进行向量运算时还有一个常用的操作是求向量的模,我们用$__abs__$特殊方法来实现,abs一般用来求一个数的绝对值,向量用不到,用来求模刚好合适。使用math模块中的hypot方法计算$\sqrt(x^2+y^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
|
class Vector: def __init__( self , x = 0 , y = 0 ): self .x = x self .y = y # 真假值,如果向量模为0,返回false def __bool__( self ): return bool ( abs ( self )) # 实现向量加法 def __add__( self , other): x = self .x + other.x y = self .y + other.y return Vector(x, y) # 实现向量乘法,例如r*3 def __mul__( self , scalar): return Vector( self .x * scalar, self .y * scalar) # 返回向量的模 # hypot()返回欧几里德范数 sqrt(x*x + y*y) def __abs__( self ): return hypot( self .x, self .y) |
找个例子运行下。
1
2
3
4
5
|
v = Vector( 2 , 3 ) print (v) v2 = Vector( 4 , 5 ) print (v + v2) print (v + v2 * 2 ) |
1
2
3
|
<__main__.Vector object at 0x000002B4B1843C50 > <__main__.Vector object at 0x000002B4B1843EF0 > <__main__.Vector object at 0x000002B4B1843898 > |
可以运行了,貌似是正确的,但是输出的结果很奇怪。怎么办?python中有个$__repr__$特殊方法,可以修改控制台输出的样式。
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 Vector: def __init__( self , x = 0 , y = 0 ): self .x = x self .y = y # 真假值,如果向量模为0,返回false def __bool__( self ): return bool ( abs ( self )) # 实现向量加法 def __add__( self , other): x = self .x + other.x y = self .y + other.y return Vector(x, y) # 实现向量乘法,例如r*3 def __mul__( self , scalar): return Vector( self .x * scalar, self .y * scalar) # 返回向量的模 # hypot()返回欧几里德范数 sqrt(x*x + y*y) def __abs__( self ): return hypot( self .x, self .y) # 实现__repr__方法,在控制台打印向量时会输出Vector(1, 2) # 实现__str__,使用str()返回字符串 def __repr__( self ): return 'Vector(%r, %r)' % ( self .x, self .y) |
实现了$__repr__$方法,我们就可以在控制台输出Vecotor(x,y)。与之对应的有个$__str__$方法,使用str()返回相应的字符串,展示给用户。
现在来看下之前程序运行的结果。
1
2
3
4
5
6
|
v = Vector( 2 , 3 ) print (v) v2 = Vector( 4 , 5 ) print (v + v2) print (v + v2 * 2 ) print ( abs (v)) |
1
2
3
4
|
Vector( 2 , 3 ) Vector( 6 , 8 ) Vector( 10 , 13 ) 3.605551275463989 |
效果不错。
通过实现特殊方法,自定义类型可以表现的跟内置类型一样,让我们能够写出更具有python风格的代码。
除了上面说到的几个特殊方法外,python还有差不多80多个特殊方法,比如$__len__$方法可以用来求长度,$__getitem__$可以使用haha[2]之类的操作进行切片和迭代等,同样的还有$__setitem__$。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。
原文链接:https://segmentfault.com/a/1190000012223818