python - __init__ 方法中的“self”对象来自哪里?
问题描述
我正在学习python,构造方法__init__
让我感到困惑。
class Test(object):
def __init__(self):
pass
众所周知,python 首先隐式传递一个表示对象本身的参数。在普通成员函数中是可以接受的。但让我感到困惑的是构造函数本身请求一个对象。
它看起来像下面的 c++ 代码。这段代码没有意义!参数thiz
甚至不会在构造函数之前退出!
class Test {
public:
Test(Test *thiz);
};
所以,我的问题是,为什么 pythonself
在构造函数中需要一个“不存在”的对象__init__
?
解决方案
__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__
在大多数课程中,您可以随意拨打电话。值得注意的例外包括不可变的内置类,例如tuple
和int
。
作为初始化器,__init__
显然需要访问它正在初始化的对象。您的示例对 没有任何作用self
,但是设置实例属性并做一些事情来准备对象是非常标准的。对于像您这样的情况,__init__
根本不需要显式,因为将在基类层次结构中找到缺少的函数。
推荐阅读
- java - Spark RDD 使用列表加入操作
- javascript - 确定在对象中搜索的键名
- c# - 将 ViewModel 对象绑定到数据集
- spring - Spring Boot 2 升级导致 HATEOAS href 链接与 _links 问题,现在对该链接的请求将退回到登录屏幕
- python - Matplotlib 单轴多图
- numpy-ndarray - 如何在pybind11中将numpy ndarray从f_style转换为c_style?
- node.js - 使用 SEQUELIZE Nodejs 从表名中删除双引号
- xslt - 我不能在 XSLT 1.0 上使用 xsl:key 函数
- python-3.x - 在字符串中添加反斜杠会在 Python3 中再追加一个
- python - requests.get 不关心我的代理 [http / https / sock4 / sock5]