技术杂文 | 关于Python的self最深入理解

凡是用python写过面向对象编程的都知道,你的所有的对象的方法都是需要传入一个self参数的,那么这个self到底是什么呢?

onlybugs warning:没做好放弃心理准备者请勿观看此文!

本文纯属技术类杂文 非数据分析/生物信息必会技术

Python的兴起导致了越来越多的人都开始使用这一门语言。在生物信息学领域,大数据分析领域,轻量级网站开发领域,深度学习领域等等,Python已经成为了大多数人必不可少的一个工具。

加上信息时代,到处都是Python的广告,什么不学Python就落伍了,学了Python解放双手,学Python挑战年薪百万等等,导致大家一窝蜂的涌入了py神奇的世界。

但是由于计算机知识的匮乏以及缺乏良好的教学环节,最后大家都成为了熟练工种,只能知其然而不知其所以然,听着云里雾里的计算机名词,想着自己什么时候能够称霸一方,可手上却止不住的import(生活所迫,换句话说,我其实站在了巨人的肩膀上!

后来很多人不满足于约定俗成的写法,想深入探究代码为什么这么写,也会经历一段痛苦时光。由于本人亲身经历过,所以知道探索的路上有多痛苦,所以也希望大家能继续下去。而在探索过程中,有一座名叫面向对象的大山,是你必须要面对的,本文主要讲解关于面向对象中的self到底是什么,灵感来自于某一天上午,然后今天有空就简要的探索了一下。

全文分三个大部分,第一个部分是关于类和面向对象简介并且给出简单例子,第二部分介绍对象以及self参数,第三部分简要介绍一下对象的属性(成员)。

面向对象和类

面向对象,英文叫做OOP,它本身是一种程序设计的思想。说起面向对象就必须先描述一下面向过程的概念。面向过程,就是把一切都看做过程,比如你做饭,买菜,洗菜,切菜,炒菜,然后才能吃,这就是一个面向过程的经典案例。

但是面向对象是什么呢,也拿做饭吃饭举例子,你去饭店说,我要什么菜,然后老板给你做,端上来你吃,这就是一个面向对象的过程。你会说看起来好像差不多,但是你仔细想想,在这个过程中,你(对象)只不过是执行了一些动作(方法),然后饭店老板(对象)给你做好了(方法),你吃(方法)。

整个过程中是两个对象在互作,其中又使用了一些其它对象,这个过程更像我们的现实生活。所以面向对象编程模型是一种非常非常非常流行的编程范式。

而我们使用的Python语言,大家可能都听过,一切皆对象,任何东西其实都是个对象,而我们也可以定义自己的对象。其中,定义对象的前提是需要有一个类。类可以说是从很多个个体中抽象出来的一个统称。

比如,土豆,茄子,西红柿,豆角,白菜等,我们都叫它们蔬菜,那蔬菜就是一个类。而金针菇,白玉菇,海鲜菇,口菇等等,都是蘑菇,于是它们可以是一类,蘑菇类。这么说大家就知道什么是类了吧。

下面给个简单的类的定义。

class People(object):
    def __init__(self,name,site) -> None:
        self.name = name
        self.site = site

这样我们就定义了一个最简单的类,名字叫做人,下面的init是约定俗成的写法,照着写就行,篇幅有限不多介绍为什么有init,感兴趣自己查。init被称为构造方法,就是你要创建对象的时候给对象初始化一些参数,比如这里我初始化了姓名和职位。

对象和self

上文中简单说了啥叫类,这里就要讲什么叫对象。这里不整花里胡哨的,我这么来解释对象。如果说类是你抽象出来的一个笼统概念,对象就是把笼统概念又进行了具体化,具体化的结果叫对象,这个过程叫实例化。看着还是很抽象,给个案例解释,我们上面定义的People类只能说你是笼统上的人,你应该具有名字和职位,但是你还没出生,所以你只能是抽象的,不具有实体的。

而如果我把你具体化了,你叫Ann,职位是1,那么你就是一个对象(实例).而在Python中具体是这么实现的

class People(object):
    def __init__(self,name,site) -> None:
        self.name = name
        self.site = site

    def MyName(self):
        print("My name is {} and my site is {}".format(self.name,self.site))

Ann = People('Ann',1)
Ann.MyName()

# My name is Ann and my site is 1

这里就是一个简单的实例化过程,我给每个人提供了一个动作,这种动作,我们一般使用函数来实现,称为方法,其实就是函数罢了。

上面就是把一个对象进行实例化的过程,并且让这个对象具有说你叫什么的动作。面向对象好就好在一个类可以多个实例化

Ann = People('Ann',1)
Dnn = People("Dnn",2)
Gnn = People("Gnn",1)

Ann.MyName()
Dnn.MyName()
Gnn.MyName()

# My name is Ann and my site is 1
# My name is Dnn and my site is 2
# My name is Gnn and my site is 1

这里通过实例化了三个人,并且让他们都自报家门展示了什么叫对象和类的实例化。

接下来就是最关键的,self到底是啥?

class People(object):
    def __init__(self,name,site) -> None:
        self.name = name
        self.site = site

    def MyName(self):
        print("My name is {} and my site is {}".format(self.name,self.site))

你可能观察到了,我们的每个动作都传了一个叫做self的参数,而且是第一个参数,这是约定俗称的,我先来说个死知识,类的所有成员方法(除了静态方法和类方法或者加了特殊装饰的方法),第一个参数必须是self如果你不知道我在说什么什么鬼方法,那你就记住,你使用的方法必须都在第一个位置写self参数。

接下来,我来解释为什么要这么做,以及self的真身。我们都知道,面向对象具有三大特性,第一个特性叫做封装,就是咱们内部玩的东西就咱们自己玩,不给外人玩。那你自己玩的时候,总得知道你要玩的东西叫啥吧,所以self的第一个作用就是能让你找到整个对象内部的方法,成员,方便咱们内部自己玩。你可以想想,如果没有了self,我想用name成员,我找都找不到。

而第二个作用,紧跟着第一个作用的最后。假如现在咱们不加self参数,咱们三个人,大家都需要在自报家门函数里调用name,那你能还能找到你自己的名字吗?你知道这name是你的还是我的啊。

最后,上点终极硬货,也就是self到底长啥样。

class Life(object):
    def __init__(self) -> None:
        self.what_life = "Life is to lie down and make some fries every day!"
        print(self)
        # print(hex(id(self.what_life)))

l1 = Life()

a1 = input("Eat ribs and elbows:")

这里我使用了一个新类,叫做生活,只有一个成员,是一个字符串,人生嘛,就是躺着和搞点薯条。然后我这里输出了self,很多人可能都没试过吧,输出self,可真是一件美事啊。

<__main__.Life object at 0x0000028F01C2D1C0>
Eat ribs and elbows:

这就是我们的self,翻译翻译,它是啥啊,它是Life的一个对象,它在哪呢?在内存地址为0x0000028F01C2D1C0的地方。接下来,我就带大家去看看,这self到底长个什么锤子样?

这里我使用了xdbg,因为python是64位的,所以没法使用OD,


image.png

看到了吗,这里的最上面一行开始,就是我们的self的真身了,由于我没读过Python源码,所以我下面的都是推论。Python的对象首先肯定是堆区的(废话,正经人谁把对象放栈里啊),然后对象应该具有唯一标识符的,推测是前面的01位置,然后大家可以看到,这里有很多个02 8F 01 啥啥啥的东西,跟我们的对象地址很像,这就是我们下面要讲解的。

对象属性的存储

最后,简单讲讲关于Python对象是如何存储成员的,并且给个有趣的案例。

我可以改变 what_life的内容,你信不信?

class Life(object):
    def __init__(self) -> None:
        self.what_life = "Life is to lie down and make some fries every day!"
        print(self)
        print(hex(id(self.what_life)))

l1 = Life()
print(l1.what_life)
a1 = input("Eat ribs and elbows:")
print(l1.what_life)

# 正常输出
# __main__.Life object at 0x0000021621E3D1C0>
# 0x2162192b9d0
# Life is to lie down and make some fries every day!
# Eat ribs and elbows:f
# Life is to lie down and make some fries every day!

上面的代码,我使用了python的id函数,它可以把当前传入的变量地址拿出来,然后换成十六进制,就可以捕获它了。

<__main__.Life object at 0x0000013C3294D1C0>
0x13c3283b9d0
Life is to lie down and make some fries every day!
Eat ribs and elbows:
图片

注意看,这里的地址是字符串的地址哦,也就是我们的成员的地址,Python内置的字符串类型并不是原生的,也是经过修饰的字符串类型,它当然也是一个对象了。而这个地址,一定会在我们对象的原始地址中找到。

图片

这里就是我们对象的原地址,我把左边改成了偏移的显示方法,然后我找啊找,眼睛都要瞎了,终于找到了它

图片

这就是我们的第一个成员的地址了,如果我们猜错的话,这个第一个成员的地址是不会发生变化的,都在偏移量为—+140的位置,有兴趣大家可以自己试试。

最后,我来给大家强行修改一下字符串,给加个浪漫的结尾

图片

最后我们给input一个结果,然后打印出来吧

<__main__.Life object at 0x0000013C3294D1C0>
0x13c3283b9d0
Life is to lie down and make some fries every day!
Eat ribs and elbows:f
Life is to lie down and make some fries every day with you!

这个思路其实就是做破解和游戏逆向分析的思路,有兴趣大家可以自己试试。经过了这一篇文章,我相信你一定知道了两个问题的答案,首先,self到底是什么?最后,什么时候使用self参数。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,392评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,258评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,417评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,992评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,930评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,199评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,652评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,327评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,463评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,382评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,432评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,118评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,704评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,787评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,999评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,476评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,057评论 2 341

推荐阅读更多精彩内容