为什么Python在每个参数列表中都需要一个显式的self
参数?
例如,在文档中给出的类Complex中
class Complex:
def __init__(self, realpart, imagpart):
self.r = realpart
self.i = imagpart
def conjugate(self):
self.i = -self.i
x = Complex(3.0, -4.5) # 2 instead of 3?
x.conjugate() # No parameters?
我最初发现它非常令人困惑,__init__( )
似乎需要3
参数,但只用2来调用Complex( )
。
self
参数显式而非隐式的原因是什么?
答案 0 :(得分:5)
Here是GvR关于此事的好文章。它讨论了明确的self
引用为何停留的原因。
他带来的点数:
强化
的等效性foo.meth(arg) == C.meth(foo, arg)
能够将方法动态附加到类,然后可以从该类的所有新对象和现有对象中使用它们:
def meth(myself, arg):
myself.val = arg
return myself.val
# Poke the method into the class:
C.meth = meth
我鼓励您阅读本文的其余部分。这很有意思。
答案 1 :(得分:1)
关于“self”参数:它标识某个类的实例。在C ++中,例如,完全相同的事情 - 但是在幕后。
答案 2 :(得分:1)
就是这样。 Python的对象实际上只是一堆属性(属性)。其中一些是常规值,但其他是函数。除了作为其实例的属性之外,它们没有任何特殊的绑定。调用语法的方法只是一点点糖,负责为你传递第一个参数。实际上,方法只是普通函数,您可以这样调用它们,显式传递第一个参数。
我不确切地知道为什么做出这个选择,但我认为它与你可以将自由函数作为属性分配给现有对象然后将它们称为方法这一事实有关;没有明确的self
参数,这会导致更多的混淆。
该机制类似于Javascript,只是在Javascript中,隐式传递的this
参数始终作为名为this
的局部变量引入,没有显式参数,而在Python中,您可以通过显式的第一个参数选择您自己喜欢的名称 - self
不是关键字,只是一个约定。这种差异也意味着您可以更轻松地将函数用作方法 - 如果在对象上下文之外使用(或者更确切地说,在上下文中使用默认对象,通常this
,使用window
的javascript函数将会中断),但在Python中,您可以传递一个合适的对象作为第一个参数。
请注意,其他OOP风格(Java,C ++等)也会将self
/ this
参数传递给您的方法,但是它们会隐式执行,this
不会显示为显式参数。这些语言不允许将方法调用为自由函数(并且vv。,你不能使用自由函数作为方法)。
至于它被称为__init__
的原因:至少有一个优点,即您可以重命名该类而无需重命名构造函数。这使得重构更容易,更不容易出错。顺便说一句,Python并不是唯一的 - PHP使用__construct
,虽然也支持类命名的构造函数,但不再推荐使用。
答案 3 :(得分:1)
(以下内容过于简单,但应该让您了解Python对象的创建过程。)
声明
x = Complex(3.0, -4.5)
不直接致电Complex.__init__
。相反,它与以下内容有些相同:
x = Complex.__new__(Complex, 3.0, -4.5)
Complex.__init__(x, 3.0, -4.5)
你可能仍然认为这是不必要的混淆。但它以这种方式设计以获得最大的灵活性。您可以覆盖__new__
(通常只从基类继承)
做更多(或不同)的事情而不是返回类的实例。但是,大多数情况下,您不需要为了使您无需一直进行两次调用来创建和初始化一个对象,它就会被简化为将类型本身视为可调用对象的简写。一步创建和初始化对象。