>>> from env_helper import info; info()
页面更新时间: 2023-12-27 10:41:50
运行环境:
    Linux发行版本: Debian GNU/Linux 12 (bookworm)
    操作系统内核: Linux-6.1.0-16-amd64-x86_64-with-glibc2.36
    Python版本: 3.11.2

6.4. 为什么需要 self 参数

self想必大家都不陌生,在类中当定义实例方法的时候需要将第一个参数显式声明为 self,而调用的时候并不需要传人该参数。 我们可以使用 self.x 来访问实例变量,也可以在类中使用 self.m() 来访问实例方法。self的使用示例如下:

>>> class SelfTest(object):
>>>     def __init__(self, name):
>>>         self.name = name
>>>
>>>     def showself(self):
>>>         print(" here is %s" % self)
>>>
>>>     def display(self):
>>>         self.showself()
>>>         print("The name is:", self.name)
>>>
>>>
>>> st = SelfTest("instance self")
>>> st.display()
>>> print("%X"%(id(st)))
 here is <__main__.SelfTest object at 0x7f3d118a7550>
The name is: instance self
7F3D118A7550

上例中我们使用self.name来表示实例变量name,在display方法中使用self.showselfl() 来凋用实例方法showself(),并且调用的时候没有显式传人self参数。

从上述输出中可以看出,self表示的就是实例对象本身,即SelfTest类的对象在内存中 的地址。self是对对象st本身的引用。我们在调用实例方法的时候也可以直接传人实例对象: 如:SelfTest.display(st)。其实self本身并不是Python的关键字(cls也不是),可以将self替 换成任何你喜欢的名称,如this、obj等,实际效果和self是一样的(并不推荐这样做,使用 self更符合约定俗成的原则)。

也许很多人感受self最奇怪的地方就是:在方法声明的时候需要定义self作为第一个参 数,而调用方法的时候却不用传人这个参数。虽然这并不影响语言本身的使用,而且也很容 易遵循这个规则,但多多少少会在心里问一问:既然这样,为什么必须在定义方法的时候声 明self参数呢?去掉第一个参数self不是更简洁吗?就如C++中的this指针一样。我们来简 单探讨一下为什么需要self;

  1. Python在当初设计的时候借鉴了其他语言的一些特征,如Moudla-3中方法会显式 地在参数列表中传人self。Python起源于20世纪80年代末,那个时候的很多语言都有self, 如Smalltalk、Modula-3等。 Python在最开始设计的时候受到了其他语言的影响,因此借鉴 了其中的一些理念(注:即使不了解SmalltaH Modula-3也没有关系,此处只是为了说明当 初在设计Python时借鉴了其他语言的一些特点)。下面这段话摘自Guido 1998年接受的一个 访问,他自己也提到了这一点。

Andrew: What other languages or systems have influenced Python’s design?(在 Python 的设 计过程中受到了哪些语言或者系统的影响?)

Guido: There have been many. ABC was a major iofluence, of course, since I had been working on it at CWL It inspired the use of indentation to delimit blocks, which are the high-level types and parts of object implementation. I’d spent a summer at DEC’S Systems Research Center, where I was introduced to Modula-2+; the Modula-3 final report was being written there at about the same time. What I learned there showed up in Python’s exception handling, modules, and the fact that methods explicitly contain if self” in their parameter list. String slicing came from Algol-68 and Icon.

(中文翻译:有很多,当然,ABC影响最大,因为在CWI的时候我一直在研究它。它 启发了我使用缩进来分块,这些是高级的类型以及部分对象的实现。我在DEC的系统研究 中心花费了一个暑假的时间,在那里我学到了 Modula-2+。而Modula-3也是在同一时期在那 里被实现的。我在那里学到的,在Python的异常处理、模块以及方法的参数列表中显式包含 self中都有体现,而字符串的分隔则是从Algol-6 和Icon中借签的。)

  1. Python语言本身的动态性决定了使用self能够带来一定便利。下例中len表示求点到 原点距离的函数,现在有表示直角三角形的类Rtriangle,我们发现求第三边边长和len所实 现的功能其实是一样的,所以打算直接重用该方法。由于self在函数调用中是隐式传递的, 因此当直接调用全局函数len()时传人的是point对象,而当在类中调用该方法时,传入的是 类所对应的对象,使用self可以在调用的时候央定应该传入哪一个对象。

>>> import math
>>> def len(point):
>>>     return math.sqrt(point.x ** 2 + point.y ** 2)
>>> class RTriangle(object):
>>>     def __init__(self,right_angle_sideX,right_angle_sideY):
>>>         self.x = right_angle_sideX
>>>         self.y = right_angle_sideY
>>>
>>>
>>> RTriangle.len=len
>>> rt = RTriangle(3,4)
>>> rt.len()
5.0

Python属于一级对象语言(first class object),如果m是类A的一个方法,有好几种方式都可以引用该方法,如下例所示:

>>> class A:
>>>     def m(self,value):
>>>         pass
>>> A.__dict__['m']
<function __main__.A.m(self, value)>
>>> A().m.__func__
<function __main__.A.m(self, value)>

实例方法是作用于对象的,如果用户使用上述两种形式来调用方法,最简单的方式就是 将对象本身传递到该方法中去,se]f的存在保证了 A.__dtct__['m'] ( a.2 )的使用和a.(2)—致。 同时当子类檀盖了父类中的方法但仍然想调用该父类的方法的时候,可以方便地使用baseclass. methodname ( self, ) 或 super ( childclass, self) .methodname ( < argument list > ) 来实现。

3)在存在同名的局部变fl以及实例变fi的情况下使用self使得实例变量更容易被区分。

value = 'default global' class Test(object):

def __init__(self,par1):

value = par1 + '---------------'

def show(self):

print(self.value) print(value)

a = Test("instance") show()

上述程序中第一个value为全局变置,第二个为局部变量,仅仅在方法中可见,而类同 时定义了一个实例变景value。如果没有self,我们很难区分到底哪个表示局部变量,哪个表 示实例变量,有了 self这一切一目了然了。 其实关于要不要self或者要不要将self作为关键字一直是一个很有争议的问题,也有人 提了一些修正建议。但Guido认为,基于Python目前的一些特性(如类中动态添加方法,在 类风格的装饰器中没有self无法确认是返回一个静态方法还是类方法等)保留其原有设计是 个更好的选择,更何况Python的哲学是:显式优于隐式(Explicit is better than implicit.)。个 人体会是除了在定义的时候多输入几个字符外,self的存在并不会给用户带来太多困扰,我 们没有必要过分纠结于它是否应该存在这个问题。