自我之谜不用说,几乎每门Python课程都包括关于(类)类的讲座——面向对象编程语言的基本构建块之一。当您通过一些示例学习它时,您会注意到在Python类中定义的许多函数都将self作为它们的第一个参数。例如,在下面的代码片段中,我们声明了一个名为Student的类,其greet()方法将self作为第一个参数。但是,这个函数根本没有使用self,那么self从哪里来呢?这是很多初学者的第一个谜。>>>classStudent:...defgreet(self,name):...print('GoodMorning,'+name)...>>>student=Student()>>>student.greet('John')GoodMorning,John也很奇怪,我们在使用这个函数的时候,没有给self参数设置任何东西,这又是一个让我们不解的谜题。在这篇文章中,我们将与学习者分享一些Python中自我的奥秘。1.代表什么?在我们开始解决这个难题之前,我们需要了解两个基本的相关概念:类和实例。当然,解决所有这些难题需要额外的知识,而不仅仅是类和实例,我将在接下来的讨论中阐明这些知识。如果你对这两个概念都比较熟悉,可以跳过下一段,下一段只是对这两个概念的简单概述。创建一个Python类就是声明一个新的对象类型,它提供了一种将数据和功能捆绑在一起的机制。在上面的示例中,我们创建了一个名为Student的类,并使用它创建了一个名为Student的Student类型的对象。该对象称为学生类的实例。此外,类可以提供特定的功能,通常称为属性,例如示例中的greet()函数。我们使用三个内省函数(type()、isinstance()和hasattr())来检查相关信息。>>>type(Student)>>>type(student)>>>isinstance(student,Student)True>>>hasattr(Student,'greet')True我可以简单的告诉你,greet()函数中的self参数就是上面例子中的student实例。更一般地说,它是调用此函数的实例。这是支持证据:>>>classStudent:...defgreet(self,name):...print(id(self))...print('GoodMorning,'+name)...>>>student=Student()>>>student.greet('John')4546580944GoodMorning,John>>>id(student)4546580944在上面的代码中,我们修改了greet()函数,让它使用内省id()函数来sendus显示self参数的内存地址。可以看到,self参数和实例student是同一个对象,因为它们有相同的内存地址。2、为什么不需要在函数调用中设置?继续上一节展示的例子,当我们使用实例student调用greet()函数时,这个函数通常被称为实例方法——某个类的方法实例可用的函数。然而,如果我们检查这个属性的类型,就会发现一些不同的东西。>>>student=Student()>>>student.greet>上面说了实例student的greet属性调用的是绑定方法。具体来说,它绑定到Student类的greet属性。要准确理解这意味着什么,让我们看下面的代码:>>>Student.greet(student,'John')GoodMorning,John结??合开头的例子,你可能会注意到这段代码的三件事:function是类Student,而不是实例student。在这个调用中设置了self和name参数,这和同学调用initial函数时的self参数不同。两个函数调用产生相同的输出。它们本质上使用相同的功能。通过了解这些信息,您可能已经猜到当用实例student调用greet()函数时幕后发生了什么。如上图,当实例student调用greet('John')方法时,解释器会处理这个函数调用,因为类Student发送调用者(即实例student)和name参数(即is,'John')到打印“GoodMorning,John”的greet(self,name)函数。对于感兴趣的读者,这里有一些知识可以帮助您进一步了解这个谜团。创建Python类时,它声明的函数是该类的属性(称为函数对象)。换句话说,类“拥有”这些功能。类的实例不直接实现这些功能。相反,它们将具有绑定到类中实现的相应函数的相同属性(即实例方法)。3.self是关键字吗?似乎在所有这些定义的函数中,我们都使用self作为它们的第一个参数。有些人可能会错误地认为self是Python为这些用例保留的关键字。然而,事实并非如此。请看下面的简单例子:>>>def=5File"",line1def=5^SyntaxError:invalidsyntax>>>class=4File"",line1class=4^SyntaxError:invalidsyntax>>>self=3你可能知道,def和class是Python中的关键字,我们不能将它们用作变量名。但是,我们可以在定义函数的上下文之外使用self作为变量名,这表明它不是Python中的保留关键字。4.我们必须在这些函数声明中使用self吗?在上面的例子中,我们双重引用了greet()函数。正如我们已经讨论过的,我们将这个函数作为一个实例方法来实现,这样它就可以被这个Student类的所有实例使用。在这种情况下,self是必需的。这里有一些证据:>>>classTeacher:...defsay_hello(name):...print('Hello,'+name)...>>>teacher=Teacher()>>>teacher.say_hello('John')Traceback(最近调用最后):文件“”,第1行,在TypeError:say_hello()接受1个位置参数,但2个在此处重新进行了一些分析。如前所述,当实例teacher调用say_hello()方法时,会执行teacher.say_hello()函数并将实例对象teacher和'John'设置为函数调用。这就是为什么错误说“给出了2。这与只有一个参数(名称)的函数的定义相反。但是,您可能想知道与这个谜团相关的另外两件事:在声明一个instancemethod需要包含self参数,但不一定要命名为self。在这种情况下使用这个名称只是每个Python程序员都能理解的约定。这里有一个例子,可以命名为其他名称而不会引起任何问题问题。虽然它在语法上是正确的,但不建议这样做,因为它只会混淆其他Python程序员:>>>classTeacher:...defsay_hello(professor,name):...print('Hello,'+name)...>>>teacher=Teacher()>>>teacher.say_hello('John')你好,John在声明类和静态方法等其他函数时不需要使用self参数。对类和静态的解释清楚方法将是以后文章的主题。但我在这里可以展示的是,当我们声明一个类方法时,该函数确实有一些类似于在实例方法中使用self的东西,通常称为cls,来引用类对象本身。它与特定实例无关。这是一个例子:>>>classStudent:...def__init__(self,name):...self.name=name...@classmethod...defwith_names(cls,first_name,last_name):...returncls(first_name+''+last_name)...>>>student=Student.with_names('John','Smith')>>>student.name'JohnSmith'英文原文:Unlockthe4MysteriesofselfinPython|by崔永|更好的编程|