@classmethod和@staticmethod对初学者的意义
Python中有什么和意味着什么,它们有什么不同?我应该何时使用它们,为什么我应该使用它们,我应该如何使用它们?@classmethod
@staticmethod
据我所知,告诉一个类,这是一个应该继承到子类中的方法,或者......东西。但是,这有什么意义呢?为什么不直接定义类方法而不添加或或任何定义?@classmethod
@classmethod
@staticmethod
@
Python中有什么和意味着什么,它们有什么不同?我应该何时使用它们,为什么我应该使用它们,我应该如何使用它们?@classmethod
@staticmethod
据我所知,告诉一个类,这是一个应该继承到子类中的方法,或者......东西。但是,这有什么意义呢?为什么不直接定义类方法而不添加或或任何定义?@classmethod
@classmethod
@staticmethod
@
虽然 和 非常相似,但两个实体的用法略有不同:必须将对类对象的引用作为第一个参数,而不能有任何参数。classmethod
staticmethod
classmethod
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显示)。
这里我们有一个 Python 类实例的典型初始值设定项,它以典型的实例方法接收参数,具有第一个非可选参数 (),该参数 () 包含对新创建的实例的引用。__init__
self
类方法
我们有一些任务可以使用s很好地完成。classmethod
假设我们想要创建许多 Date
类实例,其日期信息来自编码为格式为 “dd-mm-yy” 的字符串的外部源。假设我们必须在项目源代码的不同位置执行此操作。
因此,我们在这里必须做的是:
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')
让我们更仔细地看一下上面的实现,并回顾一下我们在这里有什么优势:
cls
是类本身,而不是类的实例。这很酷,因为如果我们继承我们的班级,所有的孩子也会定义。Date
from_string
静态方法
怎么样?它与任何强制参数非常相似,但不采用任何强制参数(如类方法或实例方法)。staticmethod
classmethod
让我们看一下下个用例。
我们有一个日期字符串,我们想要以某种方式验证它。此任务在逻辑上也绑定到我们到目前为止使用的 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
Rostyslav Dzinko的回答非常恰当。我想我可以强调另一个原因,当你创建一个额外的构造函数时,你应该选择。@classmethod
@staticmethod
在此示例中,Rostyslav 使用 作为工厂从其他不可接受的参数创建对象。也可以按照下面的代码所示完成相同的操作:@classmethod
from_string
Date
@staticmethod
class Date:
def __init__(self, month, day, year):
self.month = month
self.day = day
self.year = year
def display(self):
return "{0}-{1}-{2}".format(self.month, self.day, self.year)
@staticmethod
def millenium(month, day):
return Date(month, day, 2000)
new_year = Date(1, 1, 2013) # Creates a new Date object
millenium_new_year = Date.millenium(1, 1) # also creates a Date object.
# Proof:
new_year.display() # "1-1-2013"
millenium_new_year.display() # "1-1-2000"
isinstance(new_year, Date) # True
isinstance(millenium_new_year, Date) # True
因此,和 都是类的实例。new_year
millenium_new_year
Date
但是,如果您仔细观察,工厂过程无论如何都是硬编码的,可以创建对象。这意味着即使类被子类化,子类仍将创建普通对象(没有子类的任何属性)。在下面的示例中可以看到这一点:Date
Date
Date
class DateTime(Date):
def display(self):
return "{0}-{1}-{2} - 00:00:00PM".format(self.month, self.day, self.year)
datetime1 = DateTime(10, 10, 1990)
datetime2 = DateTime.millenium(10, 10)
isinstance(datetime1, DateTime) # True
isinstance(datetime2, DateTime) # False
datetime1.display() # returns "10-10-1990 - 00:00:00PM"
datetime2.display() # returns "10-10-2000" because it's not a DateTime object but a Date object. Check the implementation of the millenium method on the Date class for more details.
datetime2
不是 的实例?跆拳道?好吧,这是因为使用了装饰器。DateTime
@staticmethod
在大多数情况下,这是不希望的。如果你想要的是一个知道调用它的类的 Factory 方法,那么这就是你需要的。@classmethod
重写为(这是上述代码中唯一更改的部分):Date.millenium
@classmethod
def millenium(cls, month, day):
return cls(month, day, 2000)
确保 不是硬编码的,而是学习的。 可以是任何子类。结果将正确地成为 的实例。
让我们来测试一下:class
cls
object
cls
datetime1 = DateTime(10, 10, 1990)
datetime2 = DateTime.millenium(10, 10)
isinstance(datetime1, DateTime) # True
isinstance(datetime2, DateTime) # True
datetime1.display() # "10-10-1990 - 00:00:00PM"
datetime2.display() # "10-10-2000 - 00:00:00PM"
原因是,正如你现在所知道的,它被使用了而不是@classmethod
@staticmethod