原文是*
的一则高票回答,原文链接
可能之前也有人翻译过,但是刚好自己也有疑惑,所以搬运一下,个人水平有限所以可能翻译存在误差,欢迎指正(如侵删)。
尽管classmethod
和staticmethod
非常的相似,但是两者在具体的使用上还是有着细微的差别:classmethod
必须使用类对象作为第一个参数,而staticmethod
则可以不传递任何参数。
让我们通过实际的例子来看看。
样板
让我们假设有处理日期信息的类:
class Date(object):
day = 0
month = 0
year = 0
def __init__(self, day=0, month=0, year=0):
self.day = day
self.month = month
self.year = year
这个类很显然可以被用来存储某些日期信息(不考虑时区信息;让我们假设所有的日期都用UTC
表示)
这里定义了__init__
,典型的类实例初始化方法,它作为典型的instancemethod
接受参数,其中第一个传递的必要参数是新建的实例本身。
类方法
有一些可以通过使用classmethod
很好解决的任务。
假设我们有很多('dd-mm-yyyy')
格式字符串的日期信息,想要把它们创建成Date
类实例。我们不得不在项目的不同地方做这些事情。
所以我们必须要做到:
- 分析得到的年月日字符串,把它们转化成三个整形变量或者拥有三个元素的元组的变量。
- 通过传递这些值实例化
Date
。
得到:
day, month, year = map(int, string_date.split('-'))
date1 = Date(day, month, year)
C++拥有重载的特性可以达到这种目的,但是Python缺乏此类特性。所以,python使用classmethod
的方式。让我们尝试一种另类的构造函数。
@classmethod
def from_string(cls, date_as_string):
day, month, year = map(date_as_string.split('-'))
date1 = cls(day, month, year)
return date1
date2 = Date.from_string('11-09-2012')
进一步分析一下以上代码的执行,以及它的优势:
1.在一个地方解析日期字符串并且重复使用它。
2.做到很好的封装(相对于把执行字符串解析作为一个单独的函数在任何地方执行,这里使用的方法更符合OOP
的范式)
3.cls
表示类对象,而不是类实例。这样很酷,因为如果我们继承Date
类,那么所有的子类也都将拥有from_string
这个方法。
静态方法
那么staticmethod
又是什么呢?它和classmethod
非常的相似,但是不强制要求传递参数(但是做的事与类方法或实例方法一样)。
让我们来看一个使用的例子。
我们有一个日期字符串需要以某种方式验证。这个任务与之前一样要定义在Date
类内部,但是不要求实例化它。
静态方法在这种情况下就非常有用。看一下下面这个代码片段:
@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
的使用,我们不需要访问它所属的类,它本质上就是一个函数,调用方式和调用函数一样,不同的是它不关注对象和对象内部属性。