python 进阶(7) -- @staticmethod和@classmethod


我若成佛,天下无魔


翻译

https://stackoverflow.com/questions/12179271/meaning-of-classmethod-and-staticmethod-for-beginner

在翻译的基础上加些其他地方查资料的总结


区别

@classmethod@staticmethod相类似,存在的差别在于: 1. @classmethod必须使用类对象作为第一个参数,而 @staticmethod 可以不需要参数,当成函数来使用

  1. 如果在 @staticmethod 中要调用到这个类的一些属性方法,只能直接类名.属性名或类名.方法名。 而 @classmethod 因为持有 cls 参数,可以来调用类的属性,类的方法,实例化对象等

Boilerplate

下面使用一个处理日期的类来说明这两者的使用方法

class Date(object):

    def __init__(self, day=0, month=0, year=0):
        self.day = day
        self.month = month
        self.year = year

可以看到,这是我们平时见到的最简单的初始化方法,也就是典型的 instancemethod 类型方法,我们在一般类里面定义的方法都是这种类型

现在假设我们有很多 ('dd-mm-yyyy') 格式字符串的日期信息,想要把它们创建成 Date 类实例。我们不得不在项目的不同地方做这些事情

day, month, year = map(int, string_date.split('-'))
date1 = Date(day, month, year)

显然,这样会大大增加了代码的重复性

因为 python 没有 C++ 关于这些优化的重载功能,所以就引入了@classmethod,可以使用它得到下面的代码:

    @classmethod
    def from_string(cls, date_as_string):
        day, month, year = map(int, date_as_string.split('-'))
        date1 = cls(day, month, year)
        return date1

date2 = Date.from_string('11-09-2012')

通过上面的代码我们可以看出: 1. 第一个参数 cls 相当于类名 Date,也就是说,它是一个类对象,而不是类实例,注意区分 2. 做到了很好的封装,将功能函数化,更对 OOP 的口味

那么,@staticmethod 又是什么呢,其实他说上面的两种方法类型差不多,只是对参数没有了强制性的要求罢了

现在继续假设我们需要验证一个日期字符串的合法性,通常来说,我们是可以直接在类外面建立一个函数来专门处理这个的,但是想到因为它是日期方面的,是否可以放到 Date 类里面了,@staticmethod 的作用就在于此

    @staticmethod
    def is_date_valid(date_as_string):
        day, month, year = map(int, date_as_string.split('-'))
        return day <= 31 and month <= 12 and year <= 3999


is_date = Date.is_date_valid('11-09-2012')

现在正如我们了解到的staticmethod的使用,我们不需要访问它所属的类,它本质上就是一个函数,调用方式和调用函数一样,不同的是它不关注对象和对象内部属性。

可以简单的理解为只是将这个函数归一下类而已,免得其过于孤单,


总结

  1. 方法类型一共有三种:instancemethodstaticmethod and @classmethod
  2. @classmethod 必须将类对象(名字最好为 cls)作为第一个参数,而 staticmethod 本质上是函数
  3. 都是直接 类名.方法名() 来调用