Python @classmethod 装饰器

Python @classmethod 语法

@classmethod 是 Python 的一个内置装饰器,它用于将一个方法标记为类方法。类方法与普通实例方法不同,它接收类本身作为第一个参数(通常命名为 cls),而不是实例对象 self。

语法:

class MyObject:
    @classmethod
    def 方法名(cls, arg1, arg2, ...):
        # 方法体

说明:

@classmethod 需要放在方法名的上方,被 @classmethod 装饰的方法会接收类本身作为第一个参数。

  • cls(必选):表示当前类对象(非实例对象),命名约定为 cls。通过 cls,可以访问类的属性和调用其他类方法。
  • arg1, arg2, ...(可选):自定义参数。

提示:

  • 类方法可以直接通过类名调用,也可以通过实例对象调用(尽管不推荐)。
  • 类方法一般用于创建工厂方法,或处理与类状态相关的逻辑,而不是与特定实例相关的逻辑。

Python @classmethod 摘要

使用频率
官方文档 查看
相关函数 @staticmethod@property

Python @classmethod 示例

接下来,我们通过几个简单的例子来讲解一下 Python @classmethod 是如何使用的。

示例 1:@classmethod 基本用法

class Hero:
    count = 0

    def __init__(self, name, type):
        self.name = name
        self.type = type
        # 每次实例化时,类属性 count 自动加 1
        Hero.count += 1

    # 定义实例方法
    def skill(self):
        print(f'{self.name}放大招啦!')

    # 定义类方法
    @classmethod
    def getcount(cls):
        print(f'当前英雄总数: {cls.count}')

h1 = Hero('船长', '力量型')
h1.skill()
Hero.getcount()

h2 = Hero('先知', '智力型')
h2.skill()
Hero.getcount()

运行结果如下:

船长放大招啦!
1
先知放大招啦!
2

分析:

虽然实例方法可以操作类属性,但我们并不建议这样做。类方法的出现,其实就是用来操作类属性的。小伙伴们一定要记住:实例方法关联的是实例属性,类方法关联的是类属性

示例 2:@classmethod 作为工厂方法

class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author

    @classmethod
    def from_string(cls, info):
        """
        创建一个名为 from_string 的工厂方法,用于从字符串创建一个 Book 实例
        该字符串格式: '书名-作者'
        """
        title, author = info.split('-')
        return cls(title, author)         # 使用 cls() 来创建类的新实例

    def display_info(self):
        print(f'书名: {self.title}, 作者: {self.author}')

# 使用工厂方法来创建 Book 实例
book1 = Book.from_string('Python即学即用-Jack')
book1.display_info()

book2 = Book.from_string('SQL即学即用-Lucy')
book2.display_info()

运行结果如下:

书名: Python即学即用, 作者: Jack
书名: SQL即学即用, 作者: Lucy

分析:

from_string() 是一个类方法,它充当了一个工厂方法。from_string() 接收一个特定格式的字符串,解析后使用 cls(title, author) 来创建 Book 类的一个新实例。

这种模式非常有用,因为它提供了一种灵活的方式来创建对象,而无需直接调用 __init__() 方法。

示例 3:@classmethod 用于替代构造函数

import datetime

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    @classmethod
    def from_birth_year(cls, name, birth_year):
        # 根据出生年份,来创建 Person 实例
        current_year = datetime.datetime.now().year
        age = current_year - birth_year
        return cls(name, age)     # 调用 __init__ 创建实例

    def introduce(self):
        print(f'我是 {self.name},今年 {self.age} 岁')

# 使用普通的构造函数
person1 = Person('Jack', 20)
person1.introduce()

# 使用类方法替代构造函数
person2 = Person.from_birth_year('Lucy', 2001)
person2.introduce()

运行结果如下:

我是 Jack,今年 20 岁
我是 Lucy,今年 24

分析:

在这个例子中,from_birth_year() 这个类方法提供了一种便捷的方式来根据出生年份创建 Person 对象,而无需我们手动计算年龄。它内部调用 cls(name, age),这实际上是调用了 Person 类的 __init__() 方法。

示例 4:@classmethod 与继承

# 基类
class Animal:
    @classmethod
    def create_animal(cls, name):
        # 根据子类类型,来创建动物实例
        return cls(name)

    def __init__(self, name):
        self.name = name

    def speak(self):
        raise NotImplementedError('子类必须实现 speak 方法')

# 子类
class Dog(Animal):
    def speak(self):
        print(f'{self.name}:汪汪叫!')

# 子类
class Cat(Animal):
    def speak(self):
        print(f'{self.name}:喵喵叫!')

# 调用基类的类方法,来创建子类实例
dog = Dog.create_animal('旺财')
dog.speak()

cat = Cat.create_animal('咪咪')
cat.speak()

运行结果如下:

旺财:汪汪叫!
咪咪:喵喵叫!

分析:

在这个例子中,Dog 和 Cat 这两个类继承自 Animal 类。其中,Animal 类定义了一个类方法 create_animal()。

当 Dog.create_animal('旺财') 被调用时,cls 参数实际上是 Dog 类,因此 return cls(name) 创建了一个 Dog 实例。

从这个例子也可以看出类方法在多态性方面的优势。我们可以在父类中定义一个通用方法,然后由子类继承并根据自身类型进行实例化。

上一篇: Python 装饰器

下一篇: @staticmethod

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号