Python类方法:备用初始化器

示例

类方法提供了构建类实例的替代方法。为了说明,让我们看一个例子。

假设我们有一个相对简单的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+ ".")

但是,这段代码有两个主要问题:

  1. 参数first_name和last_name现在具有误导性,因为您可以输入的全名first_name。同样,如果有更多情况和/或更多参数具有这种灵活性,则if / elif / else分支会变得很烦人。

  2. 不是很重要,但仍然值得指出:如果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类。特别是,如果我们做一个子类Employee的Person,然后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.

其他参考:

  • 初学者使用Python @classmethod和@staticmethod吗?

  • https://docs.python.org/2/library/functions.html#classmethod

  • https://docs.python.org/3.5/library/functions.html#classmethod