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