一篇文章让你彻底搞清楚Python中self的含义

刚开始学习Python的类写法的时候觉得很是麻烦,为什么定义时需要而调用时又不需要,为什么不能内部简化从而减少我们敲击键盘的次数?

你看完这篇文章后就会明白所有的疑问。

self代表类的实例,而非类。

实例来说明

classTest:defprt(self):print(self)        print(self.__class__)t = Test()t.prt()

执行结果如下

<__main__.Testobjectat0x000000000284E080>

从上面的例子中可以很明显的看出,self代表的是类的实例。而self.__class__则指向类。

self不必非写成self

有很多童鞋是先学习别的语言然后学习Python的,所以总觉得self怪怪的,想写成this,可以吗?

当然可以,还是把上面的代码改写一下。

classTest:defprt(this):print(this)        print(this.__class__)t = Test()t.prt()

改成this后,运行结果完全一样。

当然,最好还是尊重约定俗成的习惯,使用self。

self可以不写吗

在Python的解释器内部,当我们调用t.prt()时,实际上Python解释成Test.prt(t),也就是说把self替换成类的实例。

有兴趣的童鞋可以把上面的t.prt()一行改写一下,运行后的实际结果完全相同。

实际上已经部分说明了self在定义时不可以省略,如果非要试一下,那么请看下面:

classTest:defprt():print(self)t = Test()t.prt()

运行时提醒错误如下:prt在定义时没有参数,但是我们运行时强行传了一个参数。

由于上面解释过了t.prt()等同于Test.prt(t),所以程序提醒我们多传了一个参数t。

Traceback (most recentcalllast):File"h.py", line6,int.prt()TypeError: prt() takes0positional arguments but1was given

当然,如果我们的定义和调用时均不传类实例是可以的,这就是类方法。

classTest:defprt():print(__class__)Test.prt()

运行结果如下

在继承时,传入的是哪个实例,就是那个传入的实例,而不是指定义了self的类的实例。

先看代码

classParent:defpprt(self):print(self)classChild(Parent):defcprt(self):print(self)c = Child()c.cprt()c.pprt()p = Parent()p.pprt()

运行结果如下

<__main__.Childobjectat0x0000000002A47080><__main__.Childobjectat0x0000000002A47080><__main__.Parentobjectat0x0000000002A47240>

解释:

运行c.cprt()时应该没有理解问题,指的是Child类的实例。

但是在运行c.pprt()时,等同于Child.pprt(c),所以self指的依然是Child类的实例,由于self中没有定义pprt()方法,所以沿着继承树往上找,发现在父类Parent中定义了pprt()方法,所以就会成功调用。

在描述符类中,self指的是描述符类的实例

不太容易理解,先看实例:

classDesc:def__get__(self, ins, cls):print('self in Desc: %s '% self )        print(self, ins, cls)classTest:x = Desc()defprt(self):print('self in Test: %s'% self)t = Test()t.prt()t.x

运行结果如下:

selfinTest: <__main__.Testobjectat0x0000000002A570B8>selfinDesc: <__main__.Descobjectat0x000000000283E208><__main__.Descobjectat0x000000000283E208> <__main__.Testobjectat0x0000000002A570B8>

大部分童鞋开始有疑问了,为什么在Desc类中定义的self不是应该是调用它的实例t吗?怎么变成了Desc类的实例了呢?

注意:此处需要睁大眼睛看清楚了,这里调用的是t.x,也就是说是Test类的实例t的属性x,由于实例t中并没有定义属性x,所以找到了类属性x,而该属性是描述符属性,为Desc类的实例而已,所以此处并没有顶用Test的任何方法。

那么我们如果直接通过类来调用属性x也可以得到相同的结果。

下面是把t.x改为Test.x运行的结果。

selfinTest: <__main__.Testobjectat0x00000000022570B8>selfinDesc: <__main__.Descobjectat0x000000000223E208><__main__.Descobjectat0x000000000223E208> None

题外话:由于在很多时候描述符类中仍然需要知道调用该描述符的实例是谁,所以在描述符类中存在第二个参数ins,用来表示调用它的类实例,所以t.x时可以看到第三行中的运行结果中第二项为<main.Test object at 0x0000000002A570B8>。而采用Test.x进行调用时,由于没有实例,所以返回None。

总结

self在定义时需要定义,但是在调用时会自动传入。

self的名字并不是规定死的,但是最好还是按照约定是用self

self总是指调用时的类的实例。

以上所有代码在Python3.4中均测试通过。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • self代表类的实例,而非类。同样,__init__也是用来初始化实例子的。 http://www.jb51.ne...
    dopami阅读 3,954评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 136,107评论 19 139
  • 没有雾霾的大北京还是相当美丽的 银杏 枫叶 以上图片均为实拍,美景可遇而不可求!
    笑笑爱笑smile阅读 3,342评论 0 1
  • 某地某医院,有一护理质量检查者正值更年期,每次检查必让护士们全身大汗淋漓,最后不知所云而止.她有自己的独特法门,她...
    世涂花开阅读 2,507评论 0 0
  • 9月20日墨尔本天气晴 今天本是一个好天气,但是昨天逛的太嗨,今天实在不想出门也不想说话,就把自己关在房间里关了大...
    青橙miss橙阅读 2,540评论 0 0

友情链接更多精彩内容