当我可以在没有注释的情况下调用构造函数时,为什么要使用@classmethod?
why should i use @classmethod when i can call the constructor in the without the annotation?
我在研究@class方法的优点,发现我们可以直接从任何方法调用构造函数,在那种情况下,为什么我们需要一个class方法。有没有我遗漏的优点。
为什么是这个代码,有什么优点?
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def fromBirthYear(cls, name, year):
return cls(name, date.today().year - year)
而不是这个代码:-
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def fromBirthYear(name, year):
return Person(name, date.today().year - year)
因为如果您从 Person 派生,fromBirthYear 将始终 return 一个 Person 对象而不是派生的 class。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def fromBirthYear(name, year):
return Person(name, year)
class Fred(Person):
pass
print(Fred.fromBirthYear('bob', 2019))
输出:
<__main__.Person object at 0x6ffffcd7c88>
您可能希望 Fred.fromBirthYear
到 return 一个 Fred 对象。
最后语言会让你做很多不该做的事情
给定
from datetime import date
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def fromBirthYear(name, year):
return Person(name, date.today().year - year)
def __repr__(self):
return f"Person('{self.name}', {self.age})"
只要您不通过 Person
:
的实例访问 fromBirthYear
,您的代码就可以找到
>>> Person("bob", 2010)
Person('bob', 10)
但是,从 Person
的 实例 调用它不会:
>>> Person("bob", 2010).fromBirthYear("bob again", 10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: fromBirthYear() takes 2 positional arguments but 3 were given
这是由于 function
类型如何实现描述符协议:通过实例访问调用其 __get__
方法(return 是 method
对象"prepasses" 底层函数的实例),同时通过 class return 访问函数本身。
为了使事情更加一致,您可以将 fromBirthYear
定义为静态方法,无论是从 class 或实例:
from datetime import date
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
@staticmethod
def fromBirthYear(name, year):
return Person(name, date.today().year - year)
def __repr__(self):
return f"Person('{self.name}', {self.age})"
>>> Person.fromBirthYear("bob", 2010)
Person('bob', 10)
>>> Person.fromBirthYear("bob", 2010).fromBirthYear("bob again", 2015)
Person('bob again', 5)
最后,class 方法的行为有点像静态方法,无论是从 class 调用还是从 class 的实例调用,接收到的参数都是一致的。但是,就像实例方法一样,它确实接收一个隐式参数:class 本身,而不是 class 的实例。这里的好处是可以在运行时确定由class方法编辑的实例return。假设您有 Person
的子class
from datetime import date
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def fromBirthYear(cls, name, year):
return cls(name, date.today().year - year)
def __repr__(self):
return f"Person('{self.name}', {self.age})"
class DifferentPerson(Person):
pass
两个class都可以用来调用fromBirthYear
,但是return值现在取决于调用它的class。
>>> type(Person.fromBirthYear("bob", 2010))
<class '__main__.Person'>
>>> type(DifferentPerson.fromBirthYear("other bog", 2010))
<class '__main__.DifferentPerson'>
我在研究@class方法的优点,发现我们可以直接从任何方法调用构造函数,在那种情况下,为什么我们需要一个class方法。有没有我遗漏的优点。
为什么是这个代码,有什么优点?
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def fromBirthYear(cls, name, year):
return cls(name, date.today().year - year)
而不是这个代码:-
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def fromBirthYear(name, year):
return Person(name, date.today().year - year)
因为如果您从 Person 派生,fromBirthYear 将始终 return 一个 Person 对象而不是派生的 class。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def fromBirthYear(name, year):
return Person(name, year)
class Fred(Person):
pass
print(Fred.fromBirthYear('bob', 2019))
输出:
<__main__.Person object at 0x6ffffcd7c88>
您可能希望 Fred.fromBirthYear
到 return 一个 Fred 对象。
最后语言会让你做很多不该做的事情
给定
from datetime import date
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def fromBirthYear(name, year):
return Person(name, date.today().year - year)
def __repr__(self):
return f"Person('{self.name}', {self.age})"
只要您不通过 Person
:
fromBirthYear
,您的代码就可以找到
>>> Person("bob", 2010)
Person('bob', 10)
但是,从 Person
的 实例 调用它不会:
>>> Person("bob", 2010).fromBirthYear("bob again", 10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: fromBirthYear() takes 2 positional arguments but 3 were given
这是由于 function
类型如何实现描述符协议:通过实例访问调用其 __get__
方法(return 是 method
对象"prepasses" 底层函数的实例),同时通过 class return 访问函数本身。
为了使事情更加一致,您可以将 fromBirthYear
定义为静态方法,无论是从 class 或实例:
from datetime import date
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
@staticmethod
def fromBirthYear(name, year):
return Person(name, date.today().year - year)
def __repr__(self):
return f"Person('{self.name}', {self.age})"
>>> Person.fromBirthYear("bob", 2010)
Person('bob', 10)
>>> Person.fromBirthYear("bob", 2010).fromBirthYear("bob again", 2015)
Person('bob again', 5)
最后,class 方法的行为有点像静态方法,无论是从 class 调用还是从 class 的实例调用,接收到的参数都是一致的。但是,就像实例方法一样,它确实接收一个隐式参数:class 本身,而不是 class 的实例。这里的好处是可以在运行时确定由class方法编辑的实例return。假设您有 Person
from datetime import date
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def fromBirthYear(cls, name, year):
return cls(name, date.today().year - year)
def __repr__(self):
return f"Person('{self.name}', {self.age})"
class DifferentPerson(Person):
pass
两个class都可以用来调用fromBirthYear
,但是return值现在取决于调用它的class。
>>> type(Person.fromBirthYear("bob", 2010))
<class '__main__.Person'>
>>> type(DifferentPerson.fromBirthYear("other bog", 2010))
<class '__main__.DifferentPerson'>