神奇的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