为什么python中的函数/方法需要self作为参数?

Why do functions/methods in python need self as parameter?

本问题已经有最佳答案,请猛点这里访问。

我可以理解为什么局部变量(self.x)需要它,但是为什么nessecary是函数中的参数?你还有什么可以代替自己的吗?

请尽可能多地用外行术语解释,我从来没有受过良好的编程教育。


默认情况下,在类的命名空间中声明的每个函数都假定其第一个参数将是对该类实例的引用。(其他类型的函数用@classmethod@staticmethod修饰以改变这个假设。)这些函数称为方法。按照惯例,python程序员将第一个参数命名为self,但python不关心您称之为什么。调用方法时,必须提供该引用。例如(用self替换为foobar,以证明self不是必需的名称):

1
2
3
4
5
6
7
8
9
class A:
    def __init__(foobar):
        foobar.x = 5

    def somefunc(foobar, y):
        print foobar.x + y

a = A()
print A.somefunc(a, 3)   # Prints 8

python提供了一些语法甜头,通过允许您调用绑定方法而不是函数本身,使对象和调用它的方法之间的链接更加明显。也就是说,a.somefunc(3)A.somefunc(a, 3)是等价的。在python术语中,A.somefunc是一个未绑定的方法,因为调用它时仍然需要一个实例:

1
2
f = A.somefunc
print f(a, 3)

相比之下,A.somefunc被称为绑定方法,因为您已经提供了用作第一个参数的实例:

1
2
f = a.somefunc
print f(3)

如果你考虑它,每种编程语言都会这样做,或者至少是最常用的语言,如PASCAL、C++或Java DO。除此之外,在大多数编程语言中,都假定this关键字,而不将其作为参数传递。考虑这些语言中的函数指针:它们与方法指针不同。

Pascal:

1
function(a: Integer): Integer;

VS

1
function(a: Integer): Integer of object;

后者考虑EDCOX1×5指针(是的,它被命名为EDCOX1×5),但它是一个隐式指针,就像在C++中的EDCOX1,7,而Python EDCOX1(5)是显式的。

C++:

1
typedef int (*mytype)(int a);

VS

1
typedef int Anyclass::(*mytype)(int a);

与Pascal不同,C++中必须指定拥有该方法的类。无论如何,这个方法指针声明声明声明了期望this或不期望this的函数之间的差异。

但是Python很重视禅宗,因为奎丘亚人很重视他们的阿玛苏威、阿玛罗莱和阿玛凯莱:

1
Explicit is better than implicit.

所以,这就是为什么您显式地看到self参数(当然必须写它),例如方法和@classmethod参数(尽管通常称为cls,因为它的目的是动态地了解类而不是实例)。python不假定方法中必须存在thisself关键字(因此,名称空间只有真正的变量-记住,尽管通常和预期的情况下,也不强制将它们命名为selfcls)。

最后,如果你得到:

1
x = AClass.amethod #unbound method

你必须称之为

1
x(aninstance, param, param2, ..., named=param, named2=param2, ...)

当得到它时:

1
x = anInstance.method #bound method, has `im_self` attribute set to the instance.

必须调用为:

1
x(param, param2, ..., named=param, named2=param2, ...)

是的,self在参数列表中是明确的,因为它没有假定一个关键字或"后门"必须存在,但在参数列表中不存在,因为每个OOP语言都有语法上的糖分(奇怪的标准,哈?).


使用self作为方法中的第一个参考完全是惯例。

在同一个类中,您可以将其称为其他内容,甚至是不一致的:

1
2
3
4
5
6
7
8
9
10
class Foo(object):
    def __init__(notself, i):
        notself.i=i             # note 'notself' instead of 'self'

    def __str__(self):
        return str(self.i)      # back to the convention  

f=Foo(22)

print f

但请不要这样做。其他人可能会读到你的代码(或者你以后读的时候自己),这会让人困惑。


这就是Python的面向对象编程实现的工作原理——使用实例的第一个参数调用实例的方法(所谓的绑定方法)。

除了实例的变量(self.x外,您还可以将它用于任何其他用途,例如调用另一个方法(self.another_method()),将此实例作为参数完全传递给其他对象(mod.some_function(3, self)),或者使用它在此类的超类(return super(ThisClass, self).this_method()中调用此方法)。

你也可以给它起一个完全不同的名字。使用pony而不是self也可以。但出于明显的原因,你不应该这样做。