Though classmethod
and staticmethod
are quite similar, there's a slight difference in usage for both entities: classmethod
must have a reference to a class object as the first parameter, whereas staticmethod
can have no parameters at all.
(尽管classmethod
和staticmethod
非常相似,但两个实体的使用情况略有不同: classmethod
必须引用类对象作为第一个参数,而staticmethod
根本没有参数。)
Example (例)
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')
Explanation (说明)
Let's assume an example of a class, dealing with date information (this will be our boilerplate):
(让我们假设一个类的例子,处理日期信息(这将是我们的样板):)
class Date(object):
def __init__(self, day=0, month=0, year=0):
self.day = day
self.month = month
self.year = year
This class obviously could be used to store information about certain dates (without timezone information; let's assume all dates are presented in UTC).
(这个类显然可以用来存储关于某些日期的信息(没有时区信息;我们假设所有日期都以UTC表示)。)
Here we have __init__
, a typical initializer of Python class instances, which receives arguments as a typical instancemethod
, having the first non-optional argument ( self
) that holds a reference to a newly created instance.
(这里我们有__init__
,它是Python类实例的典型初始化器,它接收参数作为典型的instancemethod
,具有第一个非可选参数( self
),它包含对新创建的实例的引用。)
Class Method
(类方法)
We have some tasks that can be nicely done using classmethod
s.
(我们有一些使用classmethod
可以很好地完成的任务。)
Let's assume that we want to create a lot of Date
class instances having date information coming from an outer source encoded as a string with format 'dd-mm-yyyy'.
(假设我们想要创建许多Date
类实例,其日期信息来自外部源,编码为格式为'dd-mm-yyyy'的字符串。)
Suppose we have to do this in different places in the source code of our project. (假设我们必须在项目源代码的不同位置执行此操作。)
So what we must do here is:
(所以我们必须做的是:)
- Parse a string to receive day, month and year as three integer variables or a 3-item tuple consisting of that variable.
(解析字符串以接收日,月和年作为三个整数变量或由该变量组成的3项元组。)
- Instantiate
Date
by passing those values to the initialization call. (通过将这些值传递给初始化调用来实例化Date
。)
This will look like:
(这看起来像:)
day, month, year = map(int, string_date.split('-'))
date1 = Date(day, month, year)
For this purpose, C++ can implement such a feature with overloading, but Python lacks this overloading.
(为此,C ++可以通过重载实现这样的功能,但是Python缺少这种重载。)
Instead, we can use classmethod
. (相反,我们可以使用classmethod
。)
Let's create another " constructor ". (让我们创建另一个“ 构造函数 ”。)
@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')
Let's look more carefully at the above implementation, and review what advantages we have here:
(让我们更仔细地看一下上面的实现,并回顾一下我们在这里有什么优势:)
- We've implemented date string parsing in one place and it's reusable now.
(我们在一个地方实现了日期字符串解析,现在它可以重用。)
- Encapsulation works fine here (if you think that you could implement string parsing as a single function elsewhere, this solution fits the OOP paradigm far better).
(封装在这里工作正常(如果你认为你可以在其他地方实现字符串解析作为单个函数,这个解决方案更适合OOP范例)。)
-
cls
is an object that holds the class itself , not an instance of the class. (cls
是一个保存类本身的对象,而不是类的实例。)
It's pretty cool because if we inherit our Date
class, all children will have from_string
defined also. (这很酷,因为如果我们继承Date
类,所有子from_string
定义from_string
。)
Static method
(静态方法)
What about staticmethod
?
(staticmethod
怎么样?)
It's pretty similar to classmethod
but doesn't take any obligatory parameters (like a class method or instance method does). (它与classmethod
非常相似,但不采用任何强制参数(如类方法或实例方法)。)
Let's look at the next use case.
(我们来看看下一个用例。)
We have a date string that we want to validate somehow.
(我们有一个日期字符串,我们想以某种方式验证。)
This task is also logically bound to the Date
class we've used so far, but doesn't require instantiation of it. (此任务在逻辑上也绑定到我们目前使用的Date
类,但不需要实例化它。)
Here is where staticmethod
can be useful.
(这是staticmethod
方法可能有用的地方。)
Let's look at the next piece of code: (让我们看看下一段代码:)
@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')
So, as we can see from usage of staticmethod
, we don't have any access to what the class is---it's basically just a function, called syntactically like a method, but without access to the object and its internals (fields and another methods), while classmethod does.
(因此,正如我们从staticmethod
使用中看到的那样,我们无法访问类的内容 - 它基本上只是一个函数,在语法上称为方法,但无法访问对象及其内部(字段和另一种方法),而classmethod。)