@classmethod和@staticmethod在Python中是什么意思,它们有什么不同?我应该何时使用它们,为什么要使用它们,以及如何使用它们?
据我所知,@classmethod告诉一个类,它是一个应该继承到子类中的方法,或者。。。某物然而,这有什么意义?为什么不直接定义class方法而不添加@classmethod或@staticmethod或任何@定义?
@classmethod和@staticmethod在Python中是什么意思,它们有什么不同?我应该何时使用它们,为什么要使用它们,以及如何使用它们?
据我所知,@classmethod告诉一个类,它是一个应该继承到子类中的方法,或者。。。某物然而,这有什么意义?为什么不直接定义class方法而不添加@classmethod或@staticmethod或任何@定义?
当前回答
我是这个网站的初学者,我已经阅读了以上所有答案,并得到了我想要的信息。然而,我没有投票权。所以我想从StackOverflow开始,得到我所理解的答案。
@staticmethod不需要self或cls作为方法的第一个参数@staticmethod和@classmethod包装函数可以由实例或类变量调用@staticmethod修饰函数会影响某种“不可变属性”,子类继承无法覆盖其基类函数,该基类函数由@staticmethoddecorator封装。@classmethod需要cls(类名,如果需要,可以更改变量名,但不建议)作为函数的第一个参数@classmethod总是以子类的方式使用,子类继承可能会改变基类函数的效果,即@classmethod包装的基类函数可能会被不同的子类覆盖。
其他回答
@classmethod的意思是:当调用此方法时,我们将类作为第一个参数传递,而不是该类的实例(我们通常使用方法)。这意味着您可以在该方法中使用类及其财产,而不是特定的实例。
@staticmethod意味着:当调用此方法时,我们不会将类的实例传递给它(就像我们通常使用方法一样)。这意味着您可以将函数放在类中,但不能访问该类的实例(当您的方法不使用实例时,这很有用)。
一种稍微不同的思考方式可能对某人有用。。。在超类中使用类方法来定义该方法在被不同的子类调用时的行为。当我们想要返回相同的东西而不管我们调用的子类是什么时,就使用静态方法。
我是这个网站的初学者,我已经阅读了以上所有答案,并得到了我想要的信息。然而,我没有投票权。所以我想从StackOverflow开始,得到我所理解的答案。
@staticmethod不需要self或cls作为方法的第一个参数@staticmethod和@classmethod包装函数可以由实例或类变量调用@staticmethod修饰函数会影响某种“不可变属性”,子类继承无法覆盖其基类函数,该基类函数由@staticmethoddecorator封装。@classmethod需要cls(类名,如果需要,可以更改变量名,但不建议)作为函数的第一个参数@classmethod总是以子类的方式使用,子类继承可能会改变基类函数的效果,即@classmethod包装的基类函数可能会被不同的子类覆盖。
尽管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表示)。
这里我们有__init__,这是Python类实例的典型初始化器,它作为一个典型的实例方法接收参数,具有第一个非可选参数(self),该参数保存对新创建实例的引用。
Class方法
我们有一些任务可以使用类方法很好地完成。
假设我们要创建许多Date类实例,这些实例的日期信息来自外部源,编码为“dd-mm-yyyy”格式的字符串。假设我们必须在项目源代码的不同位置执行此操作。
因此,我们在这里必须做的是:
分析一个字符串,以接收日、月和年作为三个整数变量或由该变量组成的三项元组。通过将这些值传递给初始化调用来实例化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类,所有的孩子都将定义from_string。
静态方法
静态方法呢?它与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
# usage:
is_date = Date.is_date_valid('11-09-2012')
因此,正如我们从staticmethod的用法中看到的那样,我们无法访问类是什么——它基本上只是一个函数,在语法上像方法一样被调用,但无法访问对象及其内部(字段和其他方法),而类方法确实具有这样的功能。
简而言之,@classmethod将普通方法转换为工厂方法。
让我们用一个例子来探讨一下:
class PythonBook:
def __init__(self, name, author):
self.name = name
self.author = author
def __repr__(self):
return f'Book: {self.name}, Author: {self.author}'
如果没有@classmethod,您应该一个接一个地创建实例,并且它们是分散的。
book1 = PythonBook('Learning Python', 'Mark Lutz')
In [20]: book1
Out[20]: Book: Learning Python, Author: Mark Lutz
book2 = PythonBook('Python Think', 'Allen B Dowey')
In [22]: book2
Out[22]: Book: Python Think, Author: Allen B Dowey
例如@classmethod
class PythonBook:
def __init__(self, name, author):
self.name = name
self.author = author
def __repr__(self):
return f'Book: {self.name}, Author: {self.author}'
@classmethod
def book1(cls):
return cls('Learning Python', 'Mark Lutz')
@classmethod
def book2(cls):
return cls('Python Think', 'Allen B Dowey')
测试它:
In [31]: PythonBook.book1()
Out[31]: Book: Learning Python, Author: Mark Lutz
In [32]: PythonBook.book2()
Out[32]: Book: Python Think, Author: Allen B Dowey
看见在类定义中成功创建实例,并将它们收集在一起。
总之,@classmethoddecorator将传统方法转换为工厂方法,使用classmethods可以根据需要添加尽可能多的替代构造函数。