虽然 classmethod
和 staticmethod
非常相似,但两个实体的用法略有不同:classmethod
必须引用一个类object 作为第一个参数,而 staticmethod
可以根本没有参数。
示例
class Date(object):
def __init__(self, day=0, month=0, year=0):
self.day = day
self.month = month
self.year = year
@classmethod
def from_string(cls, date_as_string):
day, month, year = map(int, date_as_string.split('-'))
date1 = cls(day, month, year)
return date1
@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
date2 = Date.from_string('11-09-2012')
is_date = Date.is_date_valid('11-09-2012')
说明
让我们假设一个类的例子,处理日期信息(这将是我们的样板):
class Date(object):
def __init__(self, day=0, month=0, year=0):
self.day = day
self.month = month
self.year = year
这个类显然可用于存储有关某些日期的信息(没有时区信息;假设所有日期都以 UTC 表示)。
这里我们有 __init__
,一个典型的 Python 类实例初始化器,它接收参数作为典型的实例方法,具有第一个非可选参数 (self
)持有对新创建实例的引用。
类方法
我们有一些任务可以使用 classmethod
s 很好地完成。
假设我们要创建许多 Date
类实例,这些实例的日期信息来自外部源,编码为格式为“dd-mm-yyyy”的字符串。假设我们必须在项目源代码的不同位置执行此操作。
所以我们必须在这里做的是:
- 解析一个字符串,将日、月和年接收为三个整数变量或由该变量组成的 3 项元组。
- 通过将这些值传递给初始化调用来实例化
Date
。
这看起来像:
day, month, year = map(int, string_date.split('-'))
date1 = Date(day, month, year)
为此,C++ 可以通过重载实现这样的功能,但 Python 缺少这种重载。相反,我们可以使用 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')
让我们更仔细地看一下上面的实现,并回顾一下我们在这里有什么优势:
- 我们在一处实现了日期字符串解析,现在可以重复使用了。
- 封装在这里工作得很好(如果您认为可以在其他地方将字符串解析实现为单个函数,那么此解决方案更适合 OOP 范式)。
cls
是类本身,而不是类的实例。这很酷,因为如果我们继承我们的 Date
类,所有的 child 也将定义 from_string
。
静态方法
静态方法
呢?它与 classmethod
非常相似,但不带任何强制性参数(就像类方法或实例方法一样)。
让我们看看下一个用例。
我们有一个想要以某种方式验证的日期字符串。该任务在逻辑上也绑定(bind)到我们目前使用的 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
# usage:
is_date = Date.is_date_valid('11-09-2012')
所以,从 staticmethod
的用法可以看出,我们无法访问类是什么——它基本上只是一个函数,在语法上像方法一样调用,但没有访问对象及其内部结构(字段和其他方法),classmethod
确实拥有。
我是一名优秀的程序员,十分优秀!