Учитывая
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})"
, ваш код работает с поиском, пока вы не получаете доступ к fromBirthYear
через экземпляр Person
:
>>> 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__
(который возвращает объект method
, который «предварительно передает» экземпляр базовой функции), тогда как доступ через класс возвращает саму функцию.
Чтобы сделать вещи более согласованными, вы можете определить fromBirthYear
как метод stati c, который всегда дает доступ к базовой функции вне зависимости от того, осуществляется ли доступ из класса или из экземпляра:
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)
Наконец, ведет себя метод класса что-то вроде метода stati c, согласованного в получаемых аргументах независимо от того, вызывается ли он из класса или из экземпляра класса. Но, как и метод экземпляра, он получает один неявный аргумент: сам класс, а не экземпляр класса. Преимущество здесь в том, что экземпляр, возвращаемый методом класса, может быть определен во время времени выполнения . Допустим, у вас есть подкласс 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
Оба класса можно использовать для вызова fromBirthYear
, но возвращаемое значение теперь зависит от класса, который его вызывает.
>>> type(Person.fromBirthYear("bob", 2010))
<class '__main__.Person'>
>>> type(DifferentPerson.fromBirthYear("other bog", 2010))
<class '__main__.DifferentPerson'>