返回介绍

建议57:为什么需要 self 参数

发布于 2024-01-30 22:19:09 字数 4049 浏览 0 评论 0 收藏 0

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

class SelfTest(object):
     def __init__(self,name):
         self.name = name
     def showself(self):
        print "self 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))

上例中我们使用self.name来表示实例变量name,在display方法中使用self.showself()来调用实例方法showself(),并且调用的时候没有显式传入self参数。程序输出如下:

self here is<__main__.SelfTest object at 0x00D67C10>
('The name is:', 'instance self')
D67C10

从上述输出中可以看出,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在最开始设计的时候受到了其他语言的影响,因此借鉴了其中的一些理念(注:即使不了解Smalltalk、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 influence,of course,since I had been working on it at CWI.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+;theModula-3final 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 “self” in their parameter list.String slicing came from Algol-68 and Icon.(有很多,当然,ABC影响最大,因为在CWI的时候我一直在研究它。它启发了我使用缩进来分块,这些是高级的类型以及部分对象的实现。我在DEC的系统研究中心花费了一个暑假的时间,在那里我学到了Modula-2+。而Modula-3也是在同一时期在那里被实现的。我在那里学到的,在Python的异常处理、模块以及方法的参数列表中显式包含self中都有体现,而字符串的分隔则是从Algol-68和Icon中借鉴的。)

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

>>> 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.right_angle_sideX = right_angle_sideX
...       self.right_angle_sideY = 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 m at 0x00D617B0>
>>> A.m.__func__
<function m at 0x00D617B0>

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

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

value = 'default global'
class Test(object):
     def __init__(self,par1):
         value = par1+"------"
         self.value = value
     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的存在并不会给用户带来太多困扰,我们没有必要过分纠结于它是否应该存在这个问题。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文