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 0x7fa1fb726840> The name is: instance self 7FA1FB726840
上例中使用 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
?
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中借签的。)
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)>
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
的存在并不会给用户带来太多困扰,
没有必要过分纠结于它是否应该存在这个问题。