方法是用来描述对象所具有的行为,例如,列表对象的追加元素、插入元素、删除元素、排序,字符串对象的分隔、连接、排版、替换,烤箱的温度设置、烘烤,等等。
在类中定义的方法可以粗略分为四大类:公有方法、私有方法、静态方法和类方法。
公有方法、私有方法一般是指属于对象的实例方法,其中私有方法的名字以两个下划线(__)开始。每个对象都有自己的公有方法和私有方法,在这两类中都可以访问属于类和对象的成员;公有方法通过对象名直接调用,私有方法不能通过对象名直接调用,只能在实例方法中通过self调用或在外部通过Python支持的特殊方式来调用。
类的所有实例方法都必须至少有一个名为self的参数,并且必须是方法的第一个形参(如果有多个形参的话),self参数代表对象本身。在类的实例方法中访问实例属性时需要以self为前缀,但在外部通过对象名调用对象方法时并不需要传递这个参数,如果在外部通过类名调用属于对象的公有方法,需要显式为该方法的self参数传递一个对象名,用来明确指定访问那个对象的数据成员。
静态方法和类方法都可以通过类名和对象名调用,单不能直接访问属于对象的成员,只能访问属于类的成员。一般将cls作为该类方法的第一个参数,表示该类自身,在调用类方法时不需要为该参数传递值。例如下面的代码所示:
1 class Root():
2
3 __total = 0 #类的属性
4
5 def __init__(self,v): #构造函数
6 self.__value = v
7 Root.__total += 1
8
9 def show(self): #普通实例方法
10 print('self.__value:',self.__value)
11 print('Root.__total:',Root.__total)
12
13 @classmethod #修饰器,声明类方法
14 def classShowTotal(cls): #类方法
15 print(cls.__total)
16
17 @staticmethod #修饰器,声明静态方法
18 def staticShowTotal(cls): #静态方法
19 print(Root.__total)
20
21 if __name__ == '__main__':
22 r = Root(3)
23 r.classShowTotal() #通过对象来调用类方法
24 r.staticShowTotal() #通过对象来调用静态方法
25 r.show() #通过对象来调用实例方法
26
27 rr = Root(5) #再创建一个Root的对象
28 Root.classShowTotal() #通过类名调用类方法
29 Root.staticShowTotal() #通过类名调用静态方法
30
31 #Root.show() #试图通过类名调用实例方法,会报错。
32 Root.show(r) #可以通过这种方法来调用实例方法并访问实例成员,以对应的实例名作为参数
33 r.show() #r.show() 的效果和 Root.show(r) 的效果是一致的
34
35 #通过类名调用实例方法时为self参数显式传递对象名
小提示:在Python中,在类中定义实例方法时将第一个参数定义为self只是一个习惯,并不必须使用self这个名字,但是一般也不建议使用别的名字。同样,属于类的方法中使用cls作为第一个参数也是一种习惯,也可以使用其他的名字作为第一个参数,虽然不建议这样做。
注意:不同对象实例的数据成员之间互不影响,是不共享的。但同一个类的所有实例方法是在不同对象之间共享的,所有对象都执行相同的代码,通过self参数来判断要处理哪个对象的数据。
拓展知识:在Python中,函数和方法是有区别的,方法一般指与特定实例绑定的函数,通过对象调用方法时,对象本身将被作为第一个参数传递过去,普通函数并不具备这个特点。
1 class Demo():
2 pass
3
4 t = Demo()
5
6 def test(self,v):
7 self.value = v
8
9 t.test = test #动态增加普通函数
10
11 print(t.test)
12
13 t.test(t,3)
14 print(t.value)
15
16 import types
17 t.test = types.MethodType(test,t) #动态增加绑定的方法
18 print(t.test)
19 t.test(5)
20 print(t.value)
还记得当初自学java的时候,学到静态方法这一块,因为对象是类实例化之后才有的,所以对象的实例也是在实例化之后才有的。而静态方法是在类创建之初就有的,如果类没有实例化,静态方法访问到实例属性就是不存在的,这显然是不合理的,故在java中就规定静态方法不能访问实例属性。Python中也是这么做的。不同编程语言之间的面向对象异曲同工啊。