为什么Python中的函数/方法需要self参数?
我能理解为什么在局部变量中需要用到这个(self.x),但是在函数的参数中为什么也需要呢?有没有其他东西可以代替self呢?
请尽量用简单易懂的语言解释一下,我没有接受过好的编程教育。
4 个回答
在方法中,使用 self
作为第一个引用完全是个约定俗成的做法。
你可以把它叫别的名字,甚至在同一个类里用不同的名字:
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
也是可以的,但这样做不太好,原因很明显。
如果你仔细想想,几乎所有编程语言都是这样做的——或者说,像Pascal、C++或Java这些常见的语言都是这样。唯一的区别是,在大多数编程语言中,this
这个关键词是默认存在的,而不是作为参数传递的。想想这些语言里的函数指针:它们和方法指针是不同的。
Pascal:
function(a: Integer): Integer;
和
function(a: Integer): Integer of object;
后者考虑了self
指针(是的,它叫self
,但它是一个隐式指针,就像C++里的this
,而Python里的self
是显式的)。
C++:
typedef int (*mytype)(int a);
和
typedef int Anyclass::(*mytype)(int a);
与Pascal的不同之处在于,在C++中你必须指定拥有这个方法的类。无论如何,这个方法指针的声明表明了一个函数是否需要this
的区别。
但是Python非常重视它的Zen,就像奇楚亚人非常重视他们的Ama Suway、Ama Llullay和Ama K'ellay一样:
Explicit is better than implicit.
所以,这就是为什么你在实例方法和@classmethod
中看到显式的self
参数(当然必须写上它)。在这里通常叫cls
,因为它的目的是动态地知道类而不是实例)。Python并不假设方法内部必须存在this
或self
这个关键词(所以,命名空间里只有真正的变量——记住,你并不被强制要求把它们命名为self
或cls
,尽管这样做是常见和被期待的)。
最后,如果你得到:
x = AClass.amethod #unbound method
你必须这样调用它:
x(aninstance, param, param2, ..., named=param, named2=param2, ...)
而得到:
x = anInstance.method #bound method, has `im_self` attribute set to the instance.
必须这样调用:
x(param, param2, ..., named=param, named2=param2, ...)
是的,self
在参数列表中是显式的,因为并不假设必须存在一个关键词或“后门”,但在参数列表中并不是这样,因为每个面向对象编程语言都有语法糖(听起来有点奇怪,对吧?)。
默认情况下,在一个类的命名空间中声明的每个函数都假设它的第一个参数是该类的一个实例的引用。为了改变这个假设,其他类型的函数会用 @classmethod
和 @staticmethod
来标记。这种函数被称为方法。通常,Python程序员会把第一个参数命名为 self
,但Python并不在意你叫它什么。当调用一个方法时,你必须提供这个引用。例如(这里用 foobar
替代 self
,是为了说明 self
不是必须的名字):
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
被称为未绑定的方法,因为在调用时它仍然需要一个实例:
f = A.somefunc
print f(a, 3)
相对而言,a.somefunc
被称为绑定的方法,因为你已经提供了要作为第一个参数使用的实例:
f = a.somefunc
print f(3)