在 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是类,无法知道具体实例) |
| | |
| ✅ 可以(通过self.__class__或self如果实例没有同名属性) | |
| 通常通过实例调用,也可以通过类调用(需手动传实例) | 可以通过类调用,也可以通过实例调用(但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)。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
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. 总结:如何选择?
| |
|---|
| |
| 可以使用类方法(cls),也可以用实例方法通过self.__class__,但类方法更清晰 |
| |
| 可以使用静态方法(@staticmethod),但那是另一个话题 |
如果方法需要操作某个具体对象的数据,用 self。如果方法主要操作类本身的数据,或者需要根据类进行多态操作,用 cls。