赞
踩
Python中 staticmethod 和 classmethod 的区别
在Python 中,有 @staticmethod、@classmethod装饰器和self、cls参数。初学时,确实不容易搞清楚。
Python中3种方式定义类方法:1、常规方式;2、@classmethod修饰方式;3、@staticmethod修饰方式。
其中:@staticmethod:静态方法装饰器;@classmethod:类方法装饰器。
常规类方法需要通过self参数隐式的传递当前类对象的实例。
@staticmethod修饰的方法定义与普通函数是一样的。
@classmethod修饰的方法class_foo()需要通过cls参数传递当前类对象。
self和cls的区别不是强制的,只是PEP8中一种编程风格,slef通常用作实例方法的第一参数,cls通常用作类方法的第一参数。即通常用self来传递当前类对象的实例,cls传递当前类对象。
一、定义的方法
class A(object): def foo(self, x): print("执行常规类 foo(%s,%s)" % (self, x)) @classmethod def class_foo(cls, x): print("执行@classmethod修饰类 class_foo(%s,%s)" % (cls, x)) @staticmethod def static_foo(x): print("执行@staicmethod修饰类 static_foo(%s)" % x) mycls = A() mycls.foo('5') mycls.class_foo('5') mycls.static_foo('5')
输出:
执行常规类 foo(<main.A object at 0x0000023CF16201D0>,5)
执行@classmethod修饰类 class_foo(<class ‘main.A’>,5)
执行@staicmethod修饰类 static_foo(5)
实际项目中的应用场景
二、常规类调用(代码续上)
mycs.foo(1)
#输出: 执行常规类 foo(<main.A object at 0x0000023CF16201D0>,1)
如果采用类对像A直接调用会出错。如下
A.foo(1)
输出:
Traceback (most recent call last):
File “”, line 1, in
TypeError: foo() missing 1 required positional argument: ‘x’
但foo可以采用下面的调用方式,显式传递实例参数a。
A.foo(mycls, 1)
输出:执行常规类 foo(<main.A object at 0x000001FE36E31050>,1)
三、静态方法调用:
要调用一个静态方法,一般使用形式是:「 类名.方法名() 」,可以采用「 实例名.方法名() 」
A.static_foo(5) #类名.方法名
输出:执行@staicmethod修饰类 static_foo(5)
mycls.static_foo(5) #实例名.方法名
输出:执行@staicmethod修饰类 static_foo(5)
通常不建议使用“实例名.方法名”这种方式。
四、类静态变量的调用方法 :「 类名.变量名 」,静态方法内部引用其它静态方法时,也是:「 类名.变量名 」
class Test(object): name = "Python演示" # 静态变量(类变量) @staticmethod # 第1个静态方法 def foo_staticmethod1(): print(Test.name + '静态方法1') # 引用静态变量 @staticmethod # 第2个静态方法 def foo_staticmethod2(): print(Test.name + '静态方法2') # 引用静态变量 print('静态方法2调用',end='') print(Test.foo_staticmethod1()) #输出:Python演示静态方法1 Test.foo_staticmethod1() #输出: #Python演示静态方法2 #静态方法2调用Python演示静态方法1 Test.foo_staticmethod2() print(Test.name) #输出:Python演示
五、静态方法内部调用普通方法,访问实例属性:普通方法和实例属性都必须通过实例对象去引用,不能直接使用类名去访问
class Test(object): def __init__(self): self.desc = "实例属性,只能通过实例对象调用" def norm_method(self): #普通方法 print('普通方法被调用!') @staticmethod def foo_staticmethod(): #静态方法,实例 instance = Test() # 获取实例属性 print(instance.desc) # 调用普通方法 instance.norm_method() Test.foo_staticmethod()
输出如下:
实例属性,只能通过实例对象调用
普通方法被调用!
五、类方法
@classmethod
装饰器 @classmethod 修饰的方法称为类方法。在使用的时候,会将其自身作为第一个参数 cls 传递给类方法本身。
1、要调用一个类方法,一般使用形式是:「 类名.方法名() 」
class Test(object):
@classmethod
def foo_cls(cls) :
print('测试')
if __name__ == '__main__' :
Test.foo_cls() #k输出:测试
和静态方法类似,也可以实例化一个类对象,通过这个对象去调用类方法,但是不建议使用这种方式。
2、调用静态变量
静态方法内部引用静态变量有两种方式,分别是:
「 类名.变量名 」
「 cls.变量名 」
需要说明的是,由于 cls 就是代表外层类本身,所以上面这两种方式等效。
class Test(object):
# 静态变量(类变量)
name = "类方法测试"
# 类方法,第一个参数为cls,代表类本身
@classmethod
def foo_classmethod(cls):
# 调用静态变量方式一
print('参数CLS调用' + cls.name)
# 调用静态变量方式二
print('类名调用' + Test.name)
Test.foo_classmethod()
输出:
参数CLS调用类方法测试
类名调用类方法测试
4、类方法内部调用普通方法,访问实例属性
需要通过 cls 变量实例化一个类对象,然后通过这个对象去调用普通方法和实例属性。
class Test(object): def __init__(self): self.val = '这是一个类属性' def norm_method(self) : # 普通方法 print('调用普通方法。') @classmethod #用@classmethod装饰器修改类方法 def foo_cls(cls) : p = cls() # 实例化 # 第一种调用方法 print(p.val) p.norm_method() # 第二种调用方法 print(cls().val) cls().norm_method() Test.foo_cls()
输出:
这是一个类属性
调用普通方法 。
这是一个类属性
调用普通方法 。
六、区别
普通方法、静态方法、类方法的区别
普通方法:第一个参数 self 代表实例对象本身,可以使用 self 直接引用定义的实例属性和普通方法;如果需要调用静态方法和类方法,通过「 类名.方法名() 」调用即可。
静态方法:使用「 类名.静态变量 」引用静态变量,利用「 类名.方法名() 」调用其他静态方法和类方法;如果需要调用普通方法,需要先实例化一个对象,然后利用对象去调用普通方法。
类方法:第一个参数 cls 代表类本身(等价),通过「 cls.静态变量 」或「 类名.静态变量 」引用静态变量,利用「 cls.方法名() 」或「 类名.方法名() 」去调用静态方法和类方法;如果需要调用普通方法,需要先实例化一个对象,然后利用对象去调用普通方法。
静态方法和类方法是针对类定义的,除了可以使用类名去调用,也可以使用实例对象去调用,但是不建议使用实例对象调用。
5.最后
一般来说,如果方法内部涉及到实例对象属性的操作,建议用普通方法;如果方法内部没有操作实例属性的操作,仅仅包含一些工具性的操作,建议使用静态方法;而如果需要对类属性,即静态变量进行限制性操作,则建议使用类方法。
参考文章:
1、https://cloud.tencent.com/developer/article/1692519,作者AirPython
2、https://www.cnblogs.com/elie/p/5876210.html,作者:Eliefly
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。