Skip to content

Python 中的 self

实例方法里,第一个参数通常命名为 self,表示当前实例。调用 obj.method(...) 时,解释器会把 obj 自动作为第一个位置参数传给 method,因此方法定义里要留出这个形参,才能在方法体内访问实例属性和其它实例方法

这与 Java、C++ 等语言里隐式的 this 不同:Python 把「当前对象」显式写在参数列表里(名字习惯叫 self,见下文)。

相关主题可结合 类与对象构造函数 __init__静态方法 阅读。

self 是关键字吗?

不是。 self 只是约定俗成的参数名,可以改成别的名字(不推荐)。若不用 self,代码可读性差,且与社区规范不一致。

基本示例

python
class Dog:
    def __init__(self, breed):
        self.breed = breed

    def bark(self):
        print(f"{self.breed} is barking.")


d = Dog("Labrador")
d.bark()

输出:

text
Labrador is barking.

说明:

  • __init__(self, breed) 在构造实例时被调用;除 self 外你传入的实参对应后面的形参(这里只需传 breed)。self 由解释器绑定到新实例,不必在 Dog(...) 里手动传入。
  • bark(self) 通过 d.bark() 调用时,d 会作为第一个参数传给 self
  • 访问实例字段用 self.breed 等形式。

可以省略 self 吗?

若把实例方法写成没有第一个参数的普通函数,通过实例调用会报错:解释器仍会传入「当前实例」这一实参。

python
class Dog:
    def bark():
        print("Barking")


d = Dog()
# d.bark()  # 报错:多传了一个参数(实例 d)

错误信息类似:TypeError: bark() takes 0 positional arguments but 1 was given。原因是 d.bark() 等价于 Dog.bark(d) 的绑定调用,会多出一个参数。

不经过实例、直接用类对象调用,且方法确实不需要参数,则不会自动注入实例(但这就不是「实例方法」的常规用法了):

python
class Dog:
    def bark():
        print("Barking")


Dog.bark()  # 可以:没有自动传入实例

结论:需要访问实例状态或希望用 obj.method() 形式时,实例方法必须保留第一个参数(惯例命名为 self

cls、静态方法的区别

  • @classmethod:第一个参数是类本身,惯例命名为 cls,由 类.method()实例.method() 调用时传入对应类。
  • @staticmethod自动传入实例或类,行为上接近普通函数,只是挂在类命名空间下。
python
class Dog:
    def __init__(self, breed):
        self.breed = breed

    @classmethod
    def walk(cls):
        print("Dog is Walking")

    def bark(self):
        print(f"{self.breed} is barking.")

    @staticmethod
    def add(x, y):
        return x + y


Dog.walk()
d = Dog("Labrador")
d.bark()
print(Dog.add(10, 20))

输出:

text
Dog is Walking
Labrador is barking.
30

参数名不必是 self / cls(仅作演示)

下面能运行,但强烈不建议在生产代码里这样写:

python
class Dog:
    @classmethod
    def walk(myclass):
        print("Dog is Walking")

    def bark(myobject):
        print("Dog is Barking.")


Dog.walk()
d = Dog()
d.bark()

可见:起作用的是「第一个形参的位置」,而不是名字本身;名字仍应用 self / cls 表达约定。

不同实例对应不同的 self

每个实例有自己的属性,self 指向谁,就读写谁的数据:

python
class Dog:
    def __init__(self, b):
        self.breed = b

    def bark(self):
        print(f"{self.breed} is Barking.")


d1 = Dog("Labrador")
d2 = Dog("Husky")

d1.bark()
d2.bark()

输出:

text
Labrador is Barking.
Husky is Barking.

为什么不让 selfthis 一样隐式?

这是 Python 的早期设计选择:显式优于隐式——在方法签名里直接看到「会收到实例」,调用规则简单、也便于静态分析与元编程。常见问题见官方 Programming FAQ 中的说明(英文):What is self?。中文读者可查阅 常见问题 — 编程 中与类、self 相关的条目(若某小节仅有英文版,可对照英文 FAQ)。

历史上也有「是否把 self 改为关键字 / 隐式参数」的讨论,Guido van Rossum 曾明确倾向于保持显式写法;深入背景可在网上检索 Python explicit selfGuido self 等关键词。

小结

  • self:实例方法的第一个参数,代表当前实例不是保留字。
  • obj.method(a, b) 会把 obj 传给 self,再传 a, b
  • @classmethodcls@staticmethod 不要 self/cls
  • 工程里请始终使用 self / cls 命名约定。