`self`参数的目的是什么?为什么需要它?

1331 投票
26 回答
1048648 浏览
提问于 2025-04-15 22:00

考虑这个例子:

class MyClass:
    def func(self, name):
        self.name = name

我知道 self 是指 MyClass 的具体实例。但是,为什么 func 必须明确地把 self 作为一个参数呢?我们在方法的代码中为什么需要使用 self?有些其他语言会自动处理这个,或者使用特别的语法来代替。


如果想了解这个设计决策的语言无关的考虑,可以查看 为什么这个/self指针必须明确指定的好处是什么?.

如果想解决 调试问题,比如用户在方法中省略了 self 参数而导致了 TypeError,可以参考 TypeError: method() takes 1 positional argument but 2 were given。如果用户在方法体内省略了 self. 而导致了 NameError,可以考虑 如何在类中调用函数?.

26 个回答

442

让我们来看一个简单的向量类:

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

我们想要有一个方法来计算长度。如果我们想把这个方法定义在类里面,它会是什么样子呢?

    def length(self):
        return math.sqrt(self.x ** 2 + self.y ** 2)

如果我们把它定义成一个全局的方法/函数,那又会是什么样子呢?

def length_global(vector):
    return math.sqrt(vector.x ** 2 + vector.y ** 2)

整体结构保持不变。我们怎么利用这个呢?假设我们暂时没有为我们的 Vector 类写一个 length 方法,我们可以这样做:

Vector.length_new = length_global
v = Vector(3, 4)
print(v.length_new()) # 5.0

这样做是可行的,因为 length_global 的第一个参数可以在 length_new 中作为 self 参数重复使用。如果没有明确的 self,这是不可能的。


理解为什么需要明确的 self 还有另一种方式,就是看看 Python 是如何简化语法的。当你记住,基本上像这样的调用:

v_instance.length()

在内部会被转换成:

Vector.length(v_instance)

这样就很容易看出 self 的位置了。你实际上并不是在 Python 中写实例方法;你写的是类方法,这些方法必须把实例作为第一个参数。因此,你必须在某个地方明确地放置这个实例参数。

630

假设你有一个类叫做 ClassA,里面有一个方法叫 methodA,定义如下:

class ClassA:
    def methodA(self, arg1, arg2):
        ... # do something

objectA 是这个类的一个实例。

现在,当你调用 objectA.methodA(arg1, arg2) 的时候,Python 会在内部帮你把它转换成:

ClassA.methodA(objectA, arg1, arg2)

这里的 self 变量指的就是这个对象本身。

795

你需要使用 self. 的原因是因为 Python 没有特别的语法来指代实例属性。Python 选择了一种方法,让调用方法的实例自动传递给方法,但并不是自动接收:方法的第一个参数就是调用这个方法的实例。这使得方法和函数完全一样,具体用什么名字由你自己决定(虽然 self 是一个约定,大家通常会对你用其他名字表示不满)。self 对代码来说并没有特别的意义,它只是另一个对象。

Python 本可以用其他方式来区分普通名字和属性,比如像 Ruby 那样使用特殊语法,或者像 C++ 和 Java 那样要求声明,甚至可能有更不同的方式,但它没有这么做。Python 更倾向于让事情变得明确,清楚地表明每样东西是什么,虽然它并不是在所有地方都做到这一点,但对于实例属性来说,它确实做到了。这就是为什么给实例属性赋值时需要知道要赋值给哪个实例,也就是为什么需要 self.

撰写回答