跳到主要内容

Python classmethod() 函数

classmethod() 方法为给定函数返回一个类方法。

示例

class Student:
marks = 0

def compute_marks(self, obtained_marks):
marks = obtained_marks
print('获得的分数:', marks)

# 将 compute_marks() 转换为类方法
Student.print_marks = classmethod(Student.compute_marks)
Student.print_marks(88)

# 输出:获得的分数: 88

classmethod() 语法

classmethod() 方法的语法是:

classmethod(function)

在新版本的 Python 中,classmethod() 被认为是不符合 Python 风格的,因此你可以使用 @classmethod 装饰器来定义类方法。

语法是:

@classmethod
def func(cls, args...)

classmethod() 参数

classmethod() 方法接受单一参数:

  • function - 需要转换为类方法的函数

classmethod() 返回值

classmethod() 方法返回给定函数的类方法。

什么是类方法?

类方法是绑定到类而不是其对象的方法。它不需要创建类实例,很像 staticmethod

静态方法和类方法之间的区别是:

  • 静态方法不了解类,并且只处理参数
  • 类方法与类一起工作,因为它的参数始终是类本身。

类方法可以通过类和它的对象来调用。

Class.classmethod()
或者
Class().classmethod()

但无论如何,类方法总是附加到类上,第一个参数为类本身 cls。

def classMethod(cls, args...)

示例 1:使用 classmethod() 创建类方法

class Person:
age = 25

def printAge(cls):
print('年龄是:', cls.age)

# 创建 printAge 类方法
Person.printAge = classmethod(Person.printAge)

Person.printAge()

输出

年龄是: 25

这里,我们有一个类 Person,成员变量 age 被赋值为 25。

我们还有一个函数 printAge,它接受单一参数 cls 而不是我们通常使用的 self

cls 接受类 Person 作为参数,而不是 Person 的对象/实例。

现在,我们将方法 Person.printAge 作为参数传递给函数 classmethod。这将该方法转换为类方法,使其接受第一个参数为类(即 Person)。

在最后一行,我们在不创建 Person 对象的情况下调用 printAge,就像我们对静态方法做的那样。这打印了类变量 age。

何时使用类方法?

1. 工厂方法

工厂方法是指那些返回类对象(类似构造函数)以适应不同用例的方法。

它类似于 C++ 中的函数重载。由于 Python 本身没有这样的功能,因此使用了类方法和静态方法。

示例 2:使用类方法创建工厂方法

from datetime import date

# 随机人物类
class Person:
def __init__(self, name, age):
self.name = name
self.age = age

@classmethod
def fromBirthYear(cls, name, birthYear):
return cls(name, date.today().year - birthYear)

def display(self):
print(self.name + "的年龄是: " + str(self.age))

person = Person('Adam', 19)
person.display()

person1 = Person.fromBirthYear('John', 1985)
person1.display()

输出

Adam的年龄是: 19
John的年龄是: 31

这里,我们有两个类实例创建器,一个构造函数和一个 fromBirthYear 方法。

构造函数接受常规参数 name 和 age。而 fromBirthYear 接受类、name 和 birthYear,通过当前年份减去出生年份来计算当前年龄,并返回类实例。

fromBirthYear 方法将 Person 类(不是 Person 对象)作为第一个参数 cls,并通过调用 cls(name, date.today().year - birthYear) 返回构造函数,等同于 Person(name, date.today().year - birthYear)

在方法前,我们看到 @classmethod。这称为装饰器,用于将 fromBirthYear 转换为类方法,即 classmethod()

2. 在继承中正确创建实例

每当你从实现工厂方法作为类方法的类派生出一个类时,它确保了派生类的正确实例创建。

你可以为上面的示例创建一个静态方法,但它创建的对象将始终硬编码为基类。

但是,当你使用类方法时,它会创建派生类的正确实例。

示例 3:类方法如何用于继承?

from datetime import date

# 随机人物类
class Person:
def __init__(self, name, age):
self.name = name
self.age = age

@staticmethod
def fromFathersAge(name, fatherAge, fatherPersonAgeDiff):
return Person(name, date.today().year - fatherAge + fatherPersonAgeDiff)

@classmethod
def fromBirthYear(cls, name, birthYear):
return cls(name, date.today().year - birthYear)

def display(self):
print(self.name + "的年龄是: " + str(self.age))

class Man(Person):
sex = 'Male'

man = Man.fromBirthYear('John', 1985)
print(isinstance(man, Man))

man1 = Man.fromFathersAge('John', 1965, 20)
print(isinstance(man1, Man))

输出

True
False

这里,使用静态方法来创建类实例需要我们在创建时硬编码实例类型。

这在继承 PersonMan 时显然会导致问题。

fromFathersAge 方法不返回 Man 对象,而是返回其基类 Person 的对象。

这违反了面向对象编程范式。使用 fromBirthYear 作为类方法可以确保代码的面向对象性,因为它将第一个参数作为类本身并调用其工厂方法。