'self' 对象在方法 __init__ 中来自哪里?
where does the 'self' object comes from in the method __init__?
我正在学习python构造方法__init__
让我很困惑。
class Test(object):
def __init__(self):
pass
众所周知,python 首先隐式传递一个表示对象本身的参数。它在普通成员函数中是可以接受的。但是让我感到困惑的是构造函数本身请求一个对象。
它看起来像下面的 C++ 代码。这段代码没有意义!参数thiz
甚至在构造函数之前都没有退出!
class Test {
public:
Test(Test *thiz);
};
所以,我的问题是,为什么 python 在构造函数 __init__
中需要一个“不存在的”self
对象?
__init__
的行为与 class 中的任何其他正常函数一样。如果定义了它,解释器会在特定时间调用它,但它没有什么特别之处。您可以随时自己调用它,就像常规方法一样。
这里有一些事实可以帮助您看清图片:
函数对象是非数据 descriptors in python. That means that function objects have a __get__
method, but not __set__
. And if course they have a __call__
实际 运行 函数的方法。
当您将 def
语句放入 class 主体时,它会创建一个常规函数,就像在其他地方一样。您可以通过查看 type(Test.__init__)
来了解这一点。要调用 Test.__init__
,您必须手动传递 self
参数。
当您在 Test
的实例上调用 __init__
时,奇迹就会发生。例如:
a = Test()
a.__init__()
这段代码实际上调用了两次 __init__
(我们稍后会介绍)。显式的第二次调用不会将参数传递给该方法。这是因为当名称 __init__
出现在 class 而不是实例中时, a.__init__
具有特殊含义。如果 __init__
是一个描述符,解释器将不会直接 return 它,而是会对其调用 __get__
并 return 结果。这称为绑定。
a.__init__()
大致相当于type(a).__init__.__get__(a, None)()
。调用 .__get__(a, None)
return 是一个可调用对象,它是一个绑定方法。它就像一种特殊类型的偏函数,其中第一个位置参数设置为a
。您可以通过检查 type(a.__init__)
.
来查看
self
参数作为第一个 positional 参数传递给方法。因此,它不必被称为 self
。名称只是一个约定。 def __init__(this):
或 def __init__(x)
也可以。
最后,我们来讨论一下 a = Test()
是如何调用 __init__
的。 Class 对象可在 python 中调用。他们自己有一个class,叫做metaclass(通常只是type
),它实际上定义了一个__call__
方法。当您执行 Test()
时,您实际上是在调用 class.
默认情况下,class 的 __call__
方法看起来像这样(非常粗略地近似):
def __call__(cls, *args, **kwargs):
self = cls.__new__(cls, *args, **kwargs)
if isinstance(self, cls):
type(self).__init__(self, *args, **kwargs)
因此,新实例仅由 __new__
创建,而不是由 __init__
创建。后者是一个初始化器,而不是构造器或分配器。事实上,正如我之前提到的,您可以在大多数 class 上随心所欲地调用 __init__
。值得注意的例外包括不可变的内置 classes,例如 tuple
和 int
.
作为初始化程序,__init__
显然需要访问它正在初始化的对象。您的示例对 self
没有任何作用,但是设置实例属性并做一些事情来准备对象是非常标准的。对于像您这样的情况,根本不需要显式 __init__
,因为会在基础 class 层次结构中找到缺失的函数。
我正在学习python构造方法__init__
让我很困惑。
class Test(object):
def __init__(self):
pass
众所周知,python 首先隐式传递一个表示对象本身的参数。它在普通成员函数中是可以接受的。但是让我感到困惑的是构造函数本身请求一个对象。
它看起来像下面的 C++ 代码。这段代码没有意义!参数thiz
甚至在构造函数之前都没有退出!
class Test {
public:
Test(Test *thiz);
};
所以,我的问题是,为什么 python 在构造函数 __init__
中需要一个“不存在的”self
对象?
__init__
的行为与 class 中的任何其他正常函数一样。如果定义了它,解释器会在特定时间调用它,但它没有什么特别之处。您可以随时自己调用它,就像常规方法一样。
这里有一些事实可以帮助您看清图片:
函数对象是非数据 descriptors in python. That means that function objects have a __get__
method, but not __set__
. And if course they have a __call__
实际 运行 函数的方法。
当您将 def
语句放入 class 主体时,它会创建一个常规函数,就像在其他地方一样。您可以通过查看 type(Test.__init__)
来了解这一点。要调用 Test.__init__
,您必须手动传递 self
参数。
当您在 Test
的实例上调用 __init__
时,奇迹就会发生。例如:
a = Test()
a.__init__()
这段代码实际上调用了两次 __init__
(我们稍后会介绍)。显式的第二次调用不会将参数传递给该方法。这是因为当名称 __init__
出现在 class 而不是实例中时, a.__init__
具有特殊含义。如果 __init__
是一个描述符,解释器将不会直接 return 它,而是会对其调用 __get__
并 return 结果。这称为绑定。
a.__init__()
大致相当于type(a).__init__.__get__(a, None)()
。调用 .__get__(a, None)
return 是一个可调用对象,它是一个绑定方法。它就像一种特殊类型的偏函数,其中第一个位置参数设置为a
。您可以通过检查 type(a.__init__)
.
self
参数作为第一个 positional 参数传递给方法。因此,它不必被称为 self
。名称只是一个约定。 def __init__(this):
或 def __init__(x)
也可以。
最后,我们来讨论一下 a = Test()
是如何调用 __init__
的。 Class 对象可在 python 中调用。他们自己有一个class,叫做metaclass(通常只是type
),它实际上定义了一个__call__
方法。当您执行 Test()
时,您实际上是在调用 class.
默认情况下,class 的 __call__
方法看起来像这样(非常粗略地近似):
def __call__(cls, *args, **kwargs):
self = cls.__new__(cls, *args, **kwargs)
if isinstance(self, cls):
type(self).__init__(self, *args, **kwargs)
因此,新实例仅由 __new__
创建,而不是由 __init__
创建。后者是一个初始化器,而不是构造器或分配器。事实上,正如我之前提到的,您可以在大多数 class 上随心所欲地调用 __init__
。值得注意的例外包括不可变的内置 classes,例如 tuple
和 int
.
作为初始化程序,__init__
显然需要访问它正在初始化的对象。您的示例对 self
没有任何作用,但是设置实例属性并做一些事情来准备对象是非常标准的。对于像您这样的情况,根本不需要显式 __init__
,因为会在基础 class 层次结构中找到缺失的函数。