@classmethod 是 Python 中的一个装饰器,用于定义类方法。类方法的第一个参数是类本身(通常命名为 cls),而不是实例(self)。它可以通过类直接调用,也可以通过实例调用。

1. 基本语法

class NewClass:
    @classmethod
    def new_class_method(cls, arg1, arg2):
        # cls 指向类本身(而不是实例)
        print(f"这是类方法,类名: {cls.__name__}")
        return arg1 + arg2
    
print(NewClass.new_class_method(1,2))

执行以上代码结果:

这是类方法,类名: NewClass
3

2. 与实例方法、静态方法的对比

方法

类型

第一个

参数

调用方式 能否访问/修改类属性 能否访问/修改实例属性

实例

方法

self

实例调用,

也可类调用(需传实例)

可以(通过 self.__class__ 可以

方法

cls 类或实例调用 可以 不可以(没有 self

静态

方法

类或实例调用 不可以(除非显式传入) 不可以

3. 类方法调用

class Dog:
    species = "犬科类"   # 类属性

    @classmethod
    def get_species(cls):
        return cls.species

    @classmethod
     # 工厂方法:根据名字创建实例, 等价于 Dog(name)
    def create_from_name(cls, name):      
        return cls(name)   

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

# 通过类调用
print(Dog.get_species())
# 通过实例调用
d = Dog("旺财")
print(f"类别:{d.get_species()}")
print(f"名字:{d.name}")

# 作为替代构造函数
dog = Dog.create_from_name("狗蛋")
print(f"类别:{dog.get_species()}")
print(f"名字:{dog.name}")

4. 典型使用场景

4.1 工厂方法(替代构造函数)

当需要多种方式创建实例时,类方法非常有用。

import datetime

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

    @classmethod
    def from_birth_year(cls, name, birth_year): # 
        current_year = datetime.datetime.now().year
        age = current_year - birth_year
        return cls(name, age)   # 调用构造函数

    @classmethod
    def from_string(cls, data_str):
        # 从 "name,age" 字符串创建
        name, age = data_str.split(',')
        return cls(name, int(age))
    
    def printInfo(self):
        print(f"姓名:{self.name}, 年龄:{self.age}")

# 使用
p1 = Person("张三", 18)
p2 = Person.from_birth_year("李四", 2018)
p3 = Person.from_string("王五,25")

p1.printInfo()
p2.printInfo()
p3.printInfo()

执行结果如下:

姓名:张三, 年龄:18
姓名:李四, 年龄:8
姓名:王五, 年龄:25

4.2 访问/修改类属性

类方法可以安全地操作类变量,即使在继承时也能正确引用子类。

class Base:
    count = 0

    @classmethod
    def increment(cls):
        cls.count += 1
        print(f"{cls.__name__} count = {cls.count}")

class Child(Base):
    pass

Base.increment()
Child.increment()

4.3 实现多态工厂(根据子类返回不同实例)

class Person:
    @classmethod
    def create(cls,  action):
        if action == "学习":
            return Student()
        elif action == "教书":
            return Teacher()
        else:
            return cls()

class Student(Person):
    pass

class Teacher(Person):
    pass

a = Person.create("学习")
print(type(a))
b = Person.create("教书")
print(type(b))
c = Person.create("治病")
print(type(c))

4.4 用于配置或全局状态的访问

class Config:
    _settings = {"host": "epics", "port": 5064}

    @classmethod
    def get(cls, key):
        return cls._settings.get(key)

    @classmethod
    def set(cls, key, value):
        cls._settings[key] = value


Config.set("IP","192.168.0.1")
print(f"Host:{Config.get('host')}, IP:{Config.get('IP')},Port:{Config.get('port')}")

运行结果:

Host:epics, IP:192.168.0.1,Port:5064

5. 继承中的行为

类方法会遵循继承链,cls 始终指向实际调用它的类。

class Base:
    @classmethod
    def identify(cls):
        return cls.__name__

class Child(Base):
    pass

print(Base.identify())   
print(Child.identify())

运行结果:

Base
Child

6. 类方法 vs 静态方法:如何选择?

  • 需要访问类本身或类属性 → 使用 @classmethod
  • 需要访问实例属性 → 使用实例方法
  • 不需要任何类或实例上下文,只是逻辑分组 → 使用 @staticmethod

7. classmethod的完整实例

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

    def printInfo(self):
        print(f"{self.name}-{self.age}-{self.grade}")

    @classmethod
    def from_json(cls, json_str):
        import json
        data = json.loads(json_str)
        return cls(data['name'], data['age'], data['grade'])

    @classmethod
    def from_csv(cls, csv_line):
        title, author, price = csv_line.strip().split(',')
        return cls(title, author, int(price))

# 使用
json_data = '{"name": "张三", "age": "18", "grade": 2}'
stu1 = Student.from_json(json_data)

csv_data = "李四, 16 , 3"
stu2 = Student.from_csv(csv_data)

stu1.printInfo()
stu2.printInfo()

执行结果:

张三-18-2
李四- 16 -3
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐