定义 class 时参考 __init__(self) 函数中的自我约定理解实例对象

understanding instance object in reference to self convention in __init__(self) function when defining class

Python 的新手,试图准确理解 __init_(self) 函数中的 self 指的是什么。

我正在使用的一些教程将 self 描述为

referring to the instance whose method was called.

对于 OOP 的新手来说,这并不是一个微不足道的陈述。

关于 the whole backstory 为什么必须在 Python 中实际包含明确的 self,我已经阅读了很多,但需要对其含义进行简单解释说self是用来指代实例对象 ——> 那是不是说self其实指的是[=34]这个对象=] 自己刚刚创建的?也就是说,self不知何故"boots up"把内存中的class当作了一个对象?

class 的每个成员函数,包括构造函数 (__init__) 都会为 class 的特定实例(对象)调用。成员函数必须能够访问调用它们的对象。

例如在 a.f() 中,f() 必须能够访问 a。在f中,定义为f(this),this指的是a。 构造函数的特殊之处在于还没有对象 "before the dot",因为正在构造该对象。所以 this 在这种情况下指的是对象 "just being constructed"。

当您编写 myClass() 时,python 首先创建您的 class 的实例,然后立即调用 __init__() 并将此对象作为参数传递。 self 是您调用 __init__().

时内存中已定义的对象

你的倒数第二句是正确的,但最后一句不正确。它与 "booting up" 或创建对象无关 - 到那时该对象已经存在。

我认为您忽略了 self 在所有方法中使用的事实,而不仅仅是 __init__,以引用该方法所属的特定对象。

例如,如果您有一个带有 name 属性 的简单对象和一个名为 print_name 的方法,它可能如下所示:

def print_name(self):
    print(self.name)

所以这里的方法使用 self 来引用调用它的对象的属性。

简单地说,这意味着您指的是对象本地的方法或变量。

您可以将 'self' 视为引荐来源网址或指向 class 内部结构的指针,您可以通过它调用方法或 add/remove/update/delete 属性。 Class 在某种程度上是一个孤立的对象,它有自己的数据表示形式。所以基本上,self 仅被显式定义为参数,使用它您可以访问 class 内部结构。一些编程语言没有明确包含关键字 self。或某些使用此(如 C++)。看看这里:

a = 1
b = 2

class test(object):
    def __init__(self,a,b):
        self.a = a + 1
        self.b = b + 1

    def show_internals(self):
        print self.a, '\t', self.b

    def change_internals(self,a,b):
        self.a = a
        self.b = b

_my_class = test(3,4)

print a , b

_my_class.show_internals()

_my_class.change_internals(5,6)

_my_class.show_internals()

print a , b

结果是:

1 2

4 5

5 6

1 2

如您所见,使用 self 可以在对象本身内操作数据。否则你最终会编辑全局变量。

当对象被实例化时,对象本身被传递到self参数中。

因此,对象的数据绑定到对象。下面是一个示例,说明您可能希望如何可视化每个对象的数据的外观。注意“self”是如何被对象名称替换的。我并不是说下面的这个示例图是完全准确的,但希望它能起到可视化 self 用法的作用。

编辑(由于进一步的问题:你能解释一下为什么当对象被实例化时,对象本身被传递到 self 参数中吗?

将对象传递到 self 参数中,以便对象可以保留自己的数据。

虽然这可能不完全准确,但请想像这样实例化对象的过程:创建对象时,它使用 class 作为其自身数据和方法的模板。如果不将它自己的名称传递给 self 参数,class 中的属性和方法将保留为通用模板,不会引用(属于)对象。因此,通过将对象的名称传递给 self 参数,这意味着如果从一个 class 实例化 100 个对象,它们都可以跟踪自己的数据和方法。

见下图:

在幕后,对象构造实际上相当复杂。

类 也是对象,class 的类型是 type(或者子class,如果使用 metaclasses) . type有一个__call__方法负责构造实例。它的工作原理类似于:

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

请注意,以上内容仅用于演示目的。

请记住,如果函数未在 class 本身上定义,则会在其父级(由 mro 控制)上查找,并且 通常 .

最终,__new__ 必须调用 object.__new__(cls) 来分配 class cls 的新实例,否则 return 现有对象。如果现有对象属于不同的 class,则不会调用 __init__。注意,如果它return是右边class(或子class)的现有对象,__init__将被调用不止一次。对于这样的 classes,所有的工作通常在 __new__.

中完成

您可能永远不会使用任何这些,但它可能会帮助您了解幕后发生的事情。