首页 > 解决方案 > __init__ 方法中的“self”对象来自哪里?

问题描述

我正在学习python,构造方法__init__让我感到困惑。

class Test(object):
  def __init__(self):
    pass

众所周知,python 首先隐式传递一个表示对象本身的参数。在普通成员函数中是可以接受的。但让我感到困惑的是构造函数本身请求一个对象。 它看起来像下面的 c++ 代码。这段代码没有意义!参数thiz甚至不会在构造函数之前退出!

class Test {
public:
  Test(Test *thiz);
};

所以,我的问题是,为什么 pythonself在构造函数中需要一个“不存在”的对象__init__

标签: pythonclassconstructorselflanguage-design

解决方案


__init__行为与类中的任何其他正常函数一样。如果它被定义,它会在一个特殊的时间被解释器调用,但它并没有什么特别之处。您可以自己随时调用它,就像常规方法一样。

这里有一些事实可以帮助您查看图片:

函数对象是python中的非数据描述符。这意味着函数对象有一个__get__方法,但没有__set__。如果他们当然有一种__call__方法来实际运行该功能。

当您def在类主体中放置一条语句时,它会创建一个常规函数,就像在其他地方一样。您可以通过查看来了解这一点type(Test.__init__)。要调用Test.__init__,您必须手动传入一个self参数。

当您__init__调用Test. 例如:

a = Test()
a.__init__()

这段代码实际上调用__init__了两次(我们稍后会介绍)。显式的第二次调用不会将参数传递给该方法。那是因为当名称存在于类中但不存在于实例中a.__init__时具有特殊含义。__init__如果__init__是一个描述符,解释器不会直接返回它,而是会调用__get__它并返回结果。这称为绑定。

a.__init__()大致相当于type(a).__init__.__get__(a, None)()。该调用.__get__(a, None)返回作为绑定方法的可调用对象。它就像一种特殊类型的偏函数,其中第一个位置参数设置为a。你可以通过检查看到这一点type(a.__init__)

self参数作为第一个位置参数传递给方法。因此,不必调用它self。这个名字只是一个约定。def __init__(this):或者def __init__(x)也可以。

最后,让我们讨论一下如何a = Test()调用__init__. 类对象在 python 中是可调用的。他们自己有一个类,称为元类(通常只是type),它实际上定义了一个__call__方法。当你这样做时Test(),你实际上是在给班级打电话。

默认情况下,__call__类的方法看起来(非常近似)如下所示:

def __call__(cls, *args, **kwargs):
    self = cls.__new__(cls, *args, **kwargs)
    if isinstance(self, cls):
        type(self).__init__(self, *args, **kwargs)

所以一个新的实例只由创建__new__,而不是__init__。后者是初始化器,而不是构造器或分配器。事实上,正如我之前提到的,__init__在大多数课程中,您可以随意拨打电话。值得注意的例外包括不可变的内置类,例如tupleint

作为初始化器,__init__显然需要访问它正在初始化的对象。您的示例对 没有任何作用self,但是设置实例属性并做一些事情来准备对象是非常标准的。对于像您这样的情况,__init__根本不需要显式,因为将在基类层次结构中找到缺少的函数。


推荐阅读