一文讀懂Python中的self

神奇的self:

在Python類中規(guī)定,函數(shù)的第一個參數(shù)是實(shí)例對象本身澈驼,并且約定俗成走搁,把其名字寫為self耘沼。其作用相當(dāng)于java中的this,表示當(dāng)前類的對象朱盐,可以調(diào)用當(dāng)前類中的屬性和方法。

class是面向?qū)ο蟮脑O(shè)計思想菠隆,instance(也即是 object兵琳,對象)是根據(jù) class 創(chuàng)建的。

一個類(class)應(yīng)該包含數(shù)據(jù)和操作數(shù)據(jù)的方法骇径,通俗來講就是屬性和函數(shù)(即調(diào)用方法)躯肌。

類 class 中為啥用使用 self ?

在類的代碼(函數(shù))中破衔,需要訪問當(dāng)前的實(shí)例中的變量和函數(shù)清女,即訪問Instance中的:

對應(yīng)的變量(property):Instance.ProperyNam,去讀取之前的值和寫入新的值晰筛。

調(diào)用對應(yīng)函數(shù)(function):Instance.function()嫡丙,即執(zhí)行對應(yīng)的動作。

-> 而需要訪問實(shí)例的變量和調(diào)用實(shí)例的函數(shù)读第,當(dāng)然需要對應(yīng)的實(shí)例Instance對象本身曙博。

-> 而Python中就規(guī)定好了,函數(shù)的第一個參數(shù)怜瞒,就必須是實(shí)例對象本身父泳,并且建議,約定俗成吴汪,把其名字寫為self惠窄。

-> 所以,我們需要self(需要用到self)漾橙。

首先杆融,在Python中類的定義:

在python中,類是通過關(guān)鍵字 class 定義的:

class 后面緊跟類名近刘,即 Person擒贸,類名通常大寫字母開頭臀晃,緊接著是(object),表示該類是從哪個類繼承下來的,通常介劫,如果沒有合適的 繼承類徽惋,就使用 object 類,這是所有類最終都會繼承的類座韵。

classPerson(object):

????pass

將 Person類實(shí)例化险绘,創(chuàng)建實(shí)例化是通過 類名+() 實(shí)現(xiàn)的。

classPerson(object):

????pass

student = Person()??? # 創(chuàng)建類的實(shí)例化

print(student)

print(Person)

可以看到誉碴,變量 student 指向的就是一個 Person的 object宦棺,后面的 0x0000026EE434D8D0 是內(nèi)存地址,每個 object 的地址都不一樣黔帕,而 Person 本身則是一個類代咸。

也可以給實(shí)例變量綁定屬性,比如:為 student 綁定 name 和 score 屬性

classPerson(object):

????pass

student = Person()

# print(student)

# print(Person)

student.name = "Gavin"# 為實(shí)例變量 student 綁定 name 屬性?? 類似于 賦值 操作

student.score = 100??????? # 為 其綁定? score 屬性

print(student.name)

print(student.score)

上述的方法雖然可以為類的實(shí)例變量綁定屬性成黄,但是不夠方便和elegant , 由于類 可以起到模板的作用呐芥,故在創(chuàng)建實(shí)例的時候,可以將我們認(rèn)為必須綁定 屬性 強(qiáng)制填寫進(jìn)去奋岁,在python中思瘟,是通過 類中通常都會使用的一個方法,即def __init__(self) 方法闻伶,在創(chuàng)建實(shí)例變量的時候滨攻,就把 name 和 score 等屬性綁上去。

classPerson(object):

????def __init__(self,name,score):

? ? ????self.name = name

????????self.score = score

student = Person('Gavin',100)??? #? 傳入 __init__ 方法中需要的參數(shù)

print(student.name)

print(student.score)

傳入空參數(shù)的情況蓝翰,會報錯:

classPerson(object):

????def __init__(self,name,score):

????????self.name = name

????????self.score = score

student = Person()????? # 此處應(yīng)該有參數(shù)傳入光绕,卻沒有傳

print(student.name)

print(student.score)

注意:

1、__init__ 方法的第一個參數(shù)永遠(yuǎn)是 self 霎箍,表示創(chuàng)建的實(shí)例本身奇钞,因此,在 __init__ 方法的內(nèi)部漂坏,就可以把各種屬性綁定到 self景埃,因?yàn)?self 就指向創(chuàng)建的實(shí)例本身。

2顶别、使用了 __init__ 方法谷徙,在創(chuàng)建實(shí)例的時候就不能傳入 空的參數(shù)了,必須傳入與 __init__ 方法匹配的參數(shù)驯绎,但是 self 不需要傳完慧,python解釋器會自己把實(shí)例變量傳進(jìn)去。

在類中定義多個函數(shù)相互調(diào)用

classPerson(object):

????def __init__(self,x,y):

????????self.x = x

????????self.y = y

????def add(self):

????????sum = self.x + self.y

????????returnsum

????def square(self):

????????squr = pow(self.x,2)+pow(self.y,2)

????????returnsqur

????def add_square(self):

????????c = self.add()+self.square()

????????returnc

student = Person(3,4)

print(student.add())

print(student.square())

print('--------- 我是可愛的分割線-----------')

print(student.add_square())

通過上述的例子可以看出剩失,與普通的函數(shù)相比屈尼,在類中定義的函數(shù)只有兩點(diǎn)不同:

1册着、第一個參數(shù)永遠(yuǎn)是 self ,并且調(diào)用時不用傳遞該參數(shù)

2脾歧、在類中函數(shù)相互調(diào)用要加 self 甲捏,如上例中: c = self.add()+self.square(), 不加 self ,會報錯: 函數(shù)未定義鞭执,看下圖:

除此之外司顿,類的方法和普通函數(shù)沒甚區(qū)別,當(dāng)然也可以使用 默認(rèn)參數(shù)兄纺、可變參數(shù)和關(guān)鍵字參數(shù)大溜,例子如下:

classPerson(object):

????def __init__(self,x,y):

????????self.x = x

????????self.y = y

????def add(self,z=16):???????? # 設(shè)置 默認(rèn)變量 z =16,這只是個普通的局部變量,非實(shí)例變量估脆,實(shí)例變量需要

????self.z = z,這樣定義

????????sum = self.x + self.y + z

????????returnsum

????def square(self):

????????squr = pow(self.x,2)+pow(self.y,2)

????????returnsqur

????def add_square(self,z):??????? #? 調(diào)用時傳入變量钦奋,這也是個普通的局部變量,非實(shí)例變量

????????c = self.add()+self.square() + z

????????returnc

student = Person(3,4)

print(student.add())

print(student.square())

print('--------- 我是可愛的分割線-----------')

print(student.add_square(16))

看了上述的例子可能還是不明白 self 到底是個什么鬼疙赠,為啥要使用 self 這鬼東西锨苏?沒關(guān)系,往下看:

其實(shí) self 這家伙簡單的說就是把 class 中 定義的 變量和函數(shù) 變成 實(shí)例變量和實(shí)例函數(shù)棺聊,作為類 class 的成員,使得成員間能互相調(diào)用贞谓,而不需要從外部調(diào)用 數(shù)據(jù)(變量)和 方法(函數(shù))限佩,以實(shí)現(xiàn)數(shù)據(jù)的封裝,以上面的 Person 類為例:

創(chuàng)建實(shí)例的時候需要給出實(shí)例變量 x,y, 調(diào)用函數(shù)時給出 z 裸弦,調(diào)用很容易祟同,卻不知道內(nèi)部實(shí)現(xiàn)的細(xì)節(jié)。

總之理疙,類是創(chuàng)建實(shí)例的模板晕城,而實(shí)例則是一個一個具體的對象,各個實(shí)例擁有的數(shù)據(jù)都相互獨(dú)立窖贤、互不影響砖顷;方法是與實(shí)例綁定的函數(shù),和普通的函數(shù)不同赃梧,方法可以直接訪問實(shí)例的數(shù)據(jù)滤蝠。

其實(shí) self 中存儲的是實(shí)例變量和實(shí)例函數(shù)的屬性,可以理解為一個字典( dict )授嘀,如:{'name':'zhang','age':'18'}就是這些物咳。

注意只有數(shù)據(jù)屬性,并沒有創(chuàng)建新的類的方法蹄皱。 類----->通過實(shí)例化生成----對象---->(對象只是一串類似于字典的數(shù)據(jù)览闰,沒有把類的里的方法復(fù)制給你芯肤,python沒有new這個方法!)

classPerson(object):

????def __init__(self,x,y):

????????self.x = x

????????self.y = y

????def add(self,z=16):???? # 設(shè)置 z 為實(shí)例變量压鉴,即 self.z = z, z 是 class的一個成員了崖咨,而非普通局部變量

????????self.z = z

????????sum = self.x + self.y + z? # z雖然已被實(shí)例化,但是依然可以當(dāng)作 普通變量來用

????????returnsum

????def square(self):

????????squr = pow(self.x,2)+pow(self.y,2)

????????returnsqur

????def add_square(self):???????

????????c = self.add()+self.square() + self.z? # 調(diào)用實(shí)例變量 z

????????returnc

student = Person(3,4)

print(student.add())

print(student.square())

print('--------- 我是可愛的分割線-----------')

print(student.add_square())

print(student.z)????????? # 函數(shù)add 中的 z 被實(shí)例化以后晴弃,就可以利用實(shí)例化的方法訪問它

通過這個例子可以看出掩幢, z 本來是 add() 函數(shù)的默認(rèn)形參,通過將其實(shí)例化上鞠,就可以在其他函數(shù)體內(nèi)調(diào)用實(shí)例變量z

被實(shí)例化以后际邻,就可以利用實(shí)例化的方法訪問它。

那么 self 到底是什么芍阎?

classBox(object):

????def __init__(self, boxname, size, color):

????????self.boxname = boxname

????????self.size = size

????????self.color = color? # self就是用于存儲對象屬性的集合世曾,就算沒有屬性self也是必備的

????def open(self, myself):

????????print('-->用自己的myself,打開那個%s,%s的%s'% (myself.color, myself.size, myself.boxname))

????????print('-->用類自己的self谴咸,打開那個%s,%s的%s'% (self.color, self.size, self.boxname))

????def close(self):

????????print('-->關(guān)閉%s轮听,謝謝'% self.boxname)

b = Box('魔盒', '14m', '紅色')

b.close()

b.open(b)? # 本來就會自動傳一個self,現(xiàn)在傳入b岭佳,就會讓open多得到一個實(shí)例對象本身血巍,print看看是什么。

print(b.__dict__)? # 這里返回的就是self本身珊随,self存儲屬性述寡,沒有動作。

self代表類的實(shí)例叶洞,而非類鲫凶;self 就是 對象/實(shí)例 屬性集合

Box 是個類-----》self 實(shí)例化------》 b對象/ 實(shí)例

class 抽象體------》實(shí)例化------》對象/實(shí)例,含有屬性:{'boxname':'魔盒', ‘size’:‘14m’, 'color':'red'}衩辟,即 self

self 看似是整個對象螟炫,實(shí)際上清楚地描述了類就是產(chǎn)生對象的過程,描述了 self 就是得到了 對象艺晴,所以 self 內(nèi)的鍵值可以直接使用

正如自然界中一個有效的對象昼钻,必須包括:

1、描述對象的屬性封寞;2换吧、對象的方法

所以 self是必須的,也是對象中重要的特性钥星。

看下面的代碼沾瓦,感覺就更神奇了:

classBox(object):

????def myInit(mySelf, boxname, size, color):

? ? ????mySelf.boxname = boxname

????????mySelf.size = size

????????mySelf.color = color? # 自己寫一個初始化函數(shù),一樣奏效,甚至不用self命名。其它函數(shù)當(dāng)中用標(biāo)準(zhǔn)self

????????returnmySelf? # 返回給實(shí)例化過程一個對象贯莺!神奇风喇!并且含有對象屬性/字典

????# def __init__(self, boxname, size, color):

????#???? self.boxname = boxname

????#???? self.size = size

????#???? self.color = color? #注釋掉原來標(biāo)準(zhǔn)的初始化

????def open(self, myself):

????????print(self)

????????print('-->用自己的myself,打開那個%s,%s的%s'% (myself.color, myself.size, myself.boxname))

????????print('-->用類自己的self缕探,打開那個%s,%s的%s'% (myself.color, myself.size, myself.boxname))

????def close(self):

????????print('-->關(guān)閉%s魂莫,謝謝'% self.boxname)

# 經(jīng)過改造,運(yùn)行結(jié)果和標(biāo)準(zhǔn)初始化沒區(qū)別

b = Box().myInit('魔盒', '14m', '紅色')

# b = Box('魔盒', '14m', '紅色')#注釋掉原來標(biāo)準(zhǔn)的初始化方法

b.close()

b.open(b)? # 本來就會自動傳一個self爹耗,現(xiàn)在傳入b耙考,就會讓open多得到一個實(shí)例對象本身,print看看是什么潭兽。

print(b.__dict__)? # 這里返回的就是self本身倦始,self存儲屬性,沒有動作山卦。

換個角度來講鞋邑,對類的操作有:

1、定義屬性 账蓉; 2枚碗、調(diào)用方法

對類的反饋有:

1、得到屬性 铸本; 2肮雨、執(zhí)行方法

在 class 類的函數(shù)中,為什么 self是必要的箱玷,因?yàn)?self 是對象的載體酷含,可以理解成一個字典,看下面代碼:

classBox(object):

????def myInit(mySelf, boxname, size, color):

????????print(mySelf.__dict__)#顯示為{}空字典

????????mySelf.boxname = boxname

????????mySelf.__dict__['aa'] = 'w'#甚至可以像字典一樣操作

????????mySelf.size = size

????????mySelf.color = color? # 自己寫一個初始化函數(shù)汪茧,一樣奏效,甚至不用self命名。其它函數(shù)當(dāng)中用標(biāo)準(zhǔn)self

????????returnmySelf? # 返回給實(shí)例化過程一個對象限番!神奇舱污!并且含有對象屬性/字典

????# def __init__(self, boxname, size, color):

????#???? self.boxname = boxname

????#???? self.size = size

????#???? self.color = color? #注釋掉原來標(biāo)準(zhǔn)的初始化

????def open(self, myself):

????????print(self)

????????print('-->用自己的myself,打開那個%s,%s的%s'% (myself.color, myself.size, myself.boxname))

????????print('-->用類自己的self弥虐,打開那個%s,%s的%s'% (myself.color, myself.size, myself.boxname))

????def close(self):

????????print('-->關(guān)閉%s扩灯,謝謝'% self.boxname)

# 經(jīng)過改造,運(yùn)行結(jié)果和標(biāo)準(zhǔn)初始化沒區(qū)別

b = Box().myInit('魔盒', '14m', '紅色')

# b = Box('魔盒', '14m', '紅色')#注釋掉原來標(biāo)準(zhǔn)的初始化方法

b.close()

b.open(b)? # 本來就會自動傳一個self霜瘪,現(xiàn)在傳入b珠插,就會讓open多得到一個實(shí)例對象本身,print看看是什么颖对。

print(b.__dict__)? # 這里返回的就是self本身捻撑,self存儲屬性,沒有動作。

注意此處的: mySelf.__dict__['aa'] = 'w' #甚至可以像字典一樣操作顾患; 在 b.__dict__ 的結(jié)果中顯示為:'aa':'w'

故可以把 self 理解成存儲 實(shí)例化對象屬性的字典(dict), self 存儲屬性番捂,而沒有動作執(zhí)行。

self總是指調(diào)用時的類的實(shí)例江解。

python 中一些特殊的實(shí)例變量:

1设预、私有變量(private),只有內(nèi)部可以訪問,外部不能訪問犁河,私有變量是在名稱前以兩個下劃線開頭鳖枕,如:__name,其實(shí)私有變量也不是完全不能被外部訪問桨螺,不能直接訪問是因?yàn)閜ython解釋器對外把 __name 變量改成了 _類名__name,所仍然可以通過 _類名__name 來訪問 __name宾符。

2、在Python中彭谁,變量名類似__xxx__的吸奴,也就是以雙下劃線開頭,并且以雙下劃線結(jié)尾的缠局,是特殊變量则奥,特殊變量是可以直接訪問的,不是private變量狭园,所以读处,不能用__name__、__score__這樣的變量名唱矛。

3罚舱、以一個下劃線開頭的實(shí)例變量名,比如_name绎谦,這樣的實(shí)例變量外部是可以訪問的管闷,但是,按照約定俗成的規(guī)定窃肠,當(dāng)你看到這樣的變量時包个,意思就是,“雖然我可以被訪問冤留,但是碧囊,請把我視為私有變量,不要隨意訪問”纤怒。

本文轉(zhuǎn)自:https://www.php.cn/python-tutorials-427723.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末糯而,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子泊窘,更是在濱河造成了極大的恐慌熄驼,老刑警劉巖像寒,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異谜洽,居然都是意外死亡萝映,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門阐虚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來序臂,“玉大人,你說我怎么就攤上這事实束“赂眩” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵咸灿,是天一觀的道長构订。 經(jīng)常有香客問我,道長避矢,這世上最難降的妖魔是什么悼瘾? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮审胸,結(jié)果婚禮上亥宿,老公的妹妹穿的比我還像新娘。我一直安慰自己砂沛,他們只是感情好烫扼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著碍庵,像睡著了一般映企。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上静浴,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天堰氓,我揣著相機(jī)與錄音,去河邊找鬼苹享。 笑死双絮,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的富稻。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼白胀,長吁一口氣:“原來是場噩夢啊……” “哼椭赋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起或杠,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤哪怔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體认境,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡胚委,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了叉信。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片亩冬。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖硼身,靈堂內(nèi)的尸體忽然破棺而出硅急,到底是詐尸還是另有隱情,我是刑警寧澤佳遂,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布营袜,位于F島的核電站,受9級特大地震影響丑罪,放射性物質(zhì)發(fā)生泄漏荚板。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一吩屹、第九天 我趴在偏房一處隱蔽的房頂上張望跪另。 院中可真熱鬧,春花似錦祟峦、人聲如沸罚斗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽针姿。三九已至,卻和暖如春厌衙,著一層夾襖步出監(jiān)牢的瞬間距淫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工婶希, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留榕暇,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓喻杈,卻偏偏與公主長得像彤枢,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子筒饰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容