11

为什么 Pythonself在每个参数列表中都需要一个显式参数?

例如在文档中给出的类 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 个参数,但你Complex( )只用 2 个参数调用。

self参数是显式而不是隐式的原因是什么?

4

4 回答 4

8

是 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

我鼓励您阅读本文的其余部分。这很有趣。

于 2012-08-03T12:30:34.787 回答
2

就是这样。Python 的对象实际上只是一组属性(属性)。其中一些是常规值,但其他一些是函数。除了作为其实例的属性之外,它们对类没有任何特殊绑定。方法调用语法只是一点点糖,负责为您传递第一个参数。事实上,方法只是简单的函数,您可以这样调用它们,显式传递第一个参数。

我不知道做出这个选择的确切原因,但我认为这与您可以将自由函数作为属性分配给现有对象然后将它们作为方法调用这一事实有关;如果没有明确的self参数,这将导致更多的混乱。

该机制类似于 Javascript,只是在 Javascript 中,隐式传递的this参数始终作为名为 的局部变量引入this,没有显式参数,而在 Python 中,您可以通过显式第一个参数选择自己喜欢的名称 -self不是关键字,只是约定。这种差异还意味着您可以更轻松地将函数用作方法 -this如果在对象上下文(或者更确切地说,在默认对象的上下文中,通常window)之外使用,使用的 javascript 函数将中断,但在 Python 中,您可以传递合适的对象作为第一个参数。

请注意,其他 OOP 风格(Java、C++ 等)也将self/this参数传递给您的方法,但它们是隐式执行的,并且this不会显示为显式参数。这些语言虽然不允许将方法调用为自由函数(并且 vv.,您不能将自由函数用作方法)。

至于为什么叫它__init__:至少有一个优点,即您可以重命名类而不必重命名构造函数。这使得重构更容易,更不容易出错。顺便说一句,Python 并不孤单 - PHP 使用__construct,虽然也支持类命名的构造函数,但不再推荐。

于 2012-08-03T11:49:13.263 回答
1

关于“self”参数:它标识某个类的实例。例如,在 C++ 中,完成了完全相同的事情——但在幕后。

进一步阅读: http: //linuxgazette.net/issue56/orr.html

于 2012-08-03T11:37:56.807 回答
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__(通常只是从基类继承)来做更多(或不同)的事情,而不是返回类的实例。但是,大多数时候您不需要这样做,因此为了避免您一直需要进行两次调用来创建和初始化一个对象,它被包裹在将类型本身视为可调用对象的简写中一步创建和初始化对象。

于 2012-08-03T12:30:25.060 回答