当前位置:首页>python>在python中什么是 self 和 cls?

在python中什么是 self 和 cls?

  • 2026-09-23 12:12:25
在python中什么是 self 和 cls?
在 Python 中,self 和 cls 分别是实例方法和类方法的第一个参数。它们虽然名字不同,但都是一种约定俗成的命名,用来接收调用时自动传入的对象。下面详细讲解它们的异同、优劣以及使用场景。

1. 什么是 self 和 cls?

self:出现在实例方法中,代表当前实例对象(即通过实例调用方法时,该实例本身)。
cls:出现在类方法中(使用 @classmethod 装饰),代表当前类对象(即通过类或实例调用时,类本身)。
示例定义:
class MyClass:    class_attr = "我是类属性"    def instance_method(self):        print("这是实例方法,self 是:", self)    @classmethod    def class_method(cls):        print("这是类方法,cls 是:", cls)
调用:
obj = MyClass()obj.instance_method()   # self 就是 objMyClass.class_method()  # cls 就是 MyClassobj.class_method()      # 即使通过实例调用,cls 仍然是 MyClass
输出:
这是实例方法,self 是: <__main__.MyClass object at 0x...>这是类方法,cls 是: <class '__main__.MyClass'>这是类方法,cls 是: <class '__main__.MyClass'>

2. 相同点

都是方法的第一个参数:Python 会自动将调用者(实例或类)作为第一个参数传入。
都可以访问类属性:实例方法可以通过 self.__class__.class_attr 或 self.class_attr(若实例没有同名属性)访问类属性;类方法直接通过 cls.class_attr 访问。
都可以被继承:子类会继承父类的实例方法和类方法,且 self / cls 会根据实际调用者改变(多态)。

3. 不同点

对比项
实例方法(self)
类方法(cls)
装饰器
不需要
需要@classmethod
第一个参数代表什么
实例对象
类对象
能否访问实例属性
✅ 可以(self.attr)
❌ 不可以(没有self,cls是类,无法知道具体实例)
能否修改实例状态
✅ 可以
❌ 不可以
能否访问/修改类属性
✅ 可以(通过self.__class__或self如果实例没有同名属性)
✅ 可以(直接cls.attr)
调用方式
通常通过实例调用,也可以通过类调用(需手动传实例)
可以通过类调用,也可以通过实例调用(但cls始终是类)
典型用途
操作对象自身的数据和行为
操作类级别的数据、工厂方法、继承时定制行为

4. 各自优势与适用场景

4.1 实例方法(self)的优势

直接操作实例状态:适合处理每个对象特有的数据。
符合面向对象封装:将数据和操作数据的方法绑定在一起。
适用场景:修改或读取实例属性。
调用其他实例方法。
示例:
class Dog:    def __init__(self, name):        self.name = name    def bark(self):        print(f"{self.name} 在汪汪叫!")dog = Dog("旺财")dog.bark()   # 输出:旺财 在汪汪叫!

4.2 类方法(cls)的优势

不依赖实例:即使没有创建实例,也可以通过类名调用。
操作类属性:适合修改或读取属于类本身的数据。
实现多态:当子类继承并调用类方法时,cls 会指向子类,从而可以针对子类定制行为。
工厂方法:常用于根据参数创建不同子类的实例。
适用场景:
定义备选构造器(如 from_json、from_config)。
修改类属性(如计数器、配置)。
在继承体系中,子类需要定制父类方法的行为。
示例1:操作类属性
class Car:    total_cars = 0    def __init__(self):        Car.total_cars += 1   # 也可以通过 self.__class__.total_cars += 1    @classmethod    def get_total_cars(cls):        return cls.total_carsprint(Car.get_total_cars())  # 0car1 = Car()car2 = Car()print(Car.get_total_cars())  # 2
示例2:工厂方法 + 多态
class Animal:    @classmethod    def create(cls, name):        return cls(name)   # cls 会根据调用者变成子类class Dog(Animal):    def __init__(self, name):        self.name = name    def speak(self):        return f"{self.name} 汪汪"class Cat(Animal):    def __init__(self, name):        self.name = name    def speak(self):        return f"{self.name} 喵喵"dog = Dog.create("旺财")  # 调用 Animal.create,但 cls 是 Dogprint(dog.speak())        # 旺财 汪汪cat = Cat.create("咪咪")print(cat.speak())        # 咪咪 喵喵

5. 综合对比示例

class Person:    species = "人类"  # 类属性    def __init__(self, name):        self.name = name  # 实例属性    # 实例方法    def introduce(self):        print(f"我是 {self.name},属于{self.species}")  # 可以访问实例和类属性    # 类方法    @classmethod    def change_species(cls, new_species):        cls.species = new_species  # 修改类属性# 使用实例方法p1 = Person("张三")p1.introduce()  # 我是 张三,属于人类# 使用类方法(直接通过类调用)Person.change_species("新人类")p2 = Person("李四")p2.introduce()  # 我是 李四,属于新人类# 通过实例调用类方法(不推荐,但可以)p1.change_species("超人类")p2.introduce()  # 我是 李四,属于超人类

6. 总结:如何选择?

需求
选择
需要访问或修改实例属性
使用实例方法(self)
需要访问或修改类属性
可以使用类方法(cls),也可以用实例方法通过self.__class__,但类方法更清晰
不需要访问实例属性,但需要利用类的多态性
使用类方法
逻辑与类相关,但与实例无关,也不想受继承影响
可以使用静态方法(@staticmethod),但那是另一个话题
核心原则:
如果方法需要操作某个具体对象的数据,用 self。
如果方法主要操作类本身的数据,或者需要根据类进行多态操作,用 cls。

最新文章

随机文章