Python中@classmethod和@staticmethod的区别

浅谈自己对@classmethod和@staticmethod区别的理解

一、@staticmethod的理解

staticmethod是一个类级别的装饰器,用于修饰类体内的函数,让实例方法编程静态方法,它和普通函数的调用作用一样,不同的是,他不需要self实例关键字,直接通过类名来进行调用。

一个简单的小例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14

class test:

@staticmethod
def test_func(name, age):
print(name, age)


m = test()

m.test_func('syz',20)
test.test_func('syz',20)


说明:

m.test_func('syz',20)test.test_func('syz',20)效果是一样的。写成静态方法的时候往往是函数体里不需要用到实例的任何属性以及方法,这时候可以使用@staticmethod装饰器修饰,增强可读性


二、@classmethod的理解

classmethod的作用相比staticmethod来说,就非常大了。被@classmethod所修饰的方法,被称之为类方法,首先,我简单较少下classmethodstaticmethod装饰器的区别和共同点,然后在分析@classmethod所使用的一些场景。

共同点:

@classmethod@staticmethod方法都可以通过类名.方法名来调用。将所修饰的方法转变为类级别的方法。

不同点

1.@classmethod所修饰的方法的第一个参数必须为cls,也就是当前类。而@staticmethod修饰的方法的参数无需cls或者self

2.@classmethod所修饰的方法所处的功能要比@staticmethod所修饰的方法多得多。比如单例模式,工厂模式中都可以使用@classmethod装饰器进行增强。
同时@classmethod还常用来定义备选构造方法,对__init__方法进行多样的增强,这点有点跟__new__方法类似。

举个@classmethod使用的单例模式中的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#日志模块
class Logging:
_instance = {} # 定义存放实例的字典

@classmethod
def get_logger(cls, logger_name):
return cls._instance[logger_name]

@classmethod
def logger(cls, logger_name):
# 判断logger_name是否存在实例字典中,如果不存在,新生成日志实例,如果存在,直接取出,然后返回
if not cls._instance.setdefault(logger_name, None):
cls._instance[logger_name] = logging.getLogger(logger_name)
return cls._instance[logger_name]

分析:

此代码截取自我的项目中的日志模块的配置,采用单例模式,因为我对某个模块定义了多个logger,而每个logger可能再不同的模块中使用,为了避免每个模块重新生成新的日志对象,消耗内存,因此采用@classmethod方法实现单例模式。当然单例模式也可以通过__new__内置方法实现。


如果修改了实例中与类属性同名的属性,那么类属性并不会改变!

例子:

1
2
3
4
5
6
7
8
9
10
11
12

class test:

mm = 'syz'

@staticmethod
def test_func(name, age):
print(name, age)

m.mm = 'zjw'
print(m.mm)
print(test.mm)

结果:

'zjw'

'syz'

说明:

即使改变了实例中与类属性同名的属性值,但是类属性并不会变。


当然了,有关@classmethod的使用还有很多,我所理解的只是其中一小部分,它其实还可以作为工厂类的接口,用来读取或者修改工厂类本身。