類方法替代初始化器
類方法提供了構建類例項的替代方法。為了說明,讓我們看一個例子。
假設我們有一個相對簡單的 Person
類:
class Person(object):
def __init__(self, first_name, last_name, age):
self.first_name = first_name
self.last_name = last_name
self.age = age
self.full_name = first_name + " " + last_name
def greet(self):
print("Hello, my name is " + self.full_name + ".")
有一種方法可以構建此類的例項,分別指定全名而不是名字和姓氏。一種方法是將 last_name
作為可選引數,並假設如果沒有給出,我們在下面傳遞全名:
class Person(object):
def __init__(self, first_name, age, last_name=None):
if last_name is None:
self.first_name, self.last_name = first_name.split(" ", 2)
else:
self.first_name = first_name
self.last_name = last_name
self.full_name = self.first_name + " " + self.last_name
self.age = age
def greet(self):
print("Hello, my name is " + self.full_name + ".")
但是,這段程式碼有兩個主要問題:
-
引數
first_name
和last_name
現在具有誤導性,因為你可以輸入first_name
的全名。此外,如果有更多的情況和/或更多引數具有這種靈活性,if / elif / else 分支可能會很快煩人。 -
不是那麼重要,但仍值得指出:如果
last_name
是None
,但first_name
不會通過空格分成兩個或更多的東西怎麼辦?我們還有另一層輸入驗證和/或異常處理……
輸入類方法。我們將建立一個名為 from_full_name
的獨立初始化程式,而不是使用單個初始化程式,並使用(內建)classmethod
裝飾器進行裝飾。
class Person(object):
def __init__(self, first_name, last_name, age):
self.first_name = first_name
self.last_name = last_name
self.age = age
self.full_name = first_name + " " + last_name
@classmethod
def from_full_name(cls, name, age):
if " " not in name:
raise ValueError
first_name, last_name = name.split(" ", 2)
return cls(first_name, last_name, age)
def greet(self):
print("Hello, my name is " + self.full_name + ".")
注意 cls
而不是 self
作為 from_full_name
的第一個引數。類方法應用於整個類,而不是給定類的例項(這是 self
通常表示的)。所以,如果 cls
是我們的 Person
類,那麼 from_full_name
類方法的返回值是 Person(first_name, last_name, age)
,它使用 Person
的 __init__
來建立 Person
類的例項。特別是,如果我們要建立 Person
的子類 Employee
,那麼 from_full_name
也可以在 Employee
類中工作。
為了表明這是按預期工作的,讓我們以不止一種方式建立 Person
的例項,而不需要在 __init__
中進行分支:
In [2]: bob = Person("Bob", "Bobberson", 42)
In [3]: alice = Person.from_full_name("Alice Henderson", 31)
In [4]: bob.greet()
Hello, my name is Bob Bobberson.
In [5]: alice.greet()
Hello, my name is Alice Henderson.
其他參考: