Python學(xué)習(xí)筆記(2)OOP編程

中文學(xué)習(xí)網(wǎng)站: 廖雪峰的官網(wǎng)網(wǎng)站https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000

2. OOP 面向?qū)ο缶幊?/h2>

類(lèi)的訪問(wèn)限制

  • class中以雙下劃線開(kāi)頭的變量(如:_private_val)是私有變量, 不能被外部直接訪問(wèn), 但以雙下劃線開(kāi)頭和結(jié)尾的變量除外(如_name),這種是特殊變量, 能夠被外部直接訪問(wèn)
  • 私有變量的實(shí)現(xiàn)原理是: python解釋器將私有變量改成了_Classname__private_val. 所以如果直接訪問(wèn) _Classname__private_val是可以訪問(wèn)的, 但強(qiáng)烈不推薦這樣做, 因?yàn)椴煌姹镜腜ython解釋器可能會(huì)把__private_val改成不同的變量名.
  • 然而直接用a.__private_val=1, 這種賦值是能通過(guò)的, 但是注意:這是新建了一個(gè)名為_(kāi)_private_val的成員變量, 并不是原來(lái)的私有變量(已經(jīng)被改名成了_Classname__private_val)
  • _slots_ 限制用戶能對(duì)類(lèi)添加的屬性.
class Student(object):
    __slots__ = ('name', 'age') # 用tuple定義允許綁定的屬性名稱
>>> s.age = 25 # 綁定屬性'age'
>>> s.score = 99 # 綁定屬性'score'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'

注意:_slots_定義的屬性僅對(duì)當(dāng)前類(lèi)實(shí)例起作用饮笛,對(duì)繼承的子類(lèi)是不起作用的

給實(shí)例綁定方法

  • 通常是直接對(duì)類(lèi)添加方法, 但python支持只對(duì)實(shí)例綁定方法
>>> def set_age(self, age): # 定義一個(gè)函數(shù)作為實(shí)例方法
...     self.age = age
...
>>> from types import MethodType
>>> s.set_age = MethodType(set_age, s) # 給實(shí)例綁定一個(gè)方法
>>> s.set_age(25) # 調(diào)用實(shí)例方法
>>> s.age # 測(cè)試結(jié)果
25
  • 實(shí)例屬性只對(duì)當(dāng)前實(shí)例生效, 類(lèi)屬性對(duì)類(lèi)和所有類(lèi)的實(shí)例生效

@property裝飾器

  • 讀接口用@property裝飾, 寫(xiě)接口用@score.setter裝飾,score是需要裝飾的接口名字.
  • 盡管是函數(shù), 但調(diào)用時(shí)不需要帶括號(hào), 把它當(dāng)做一個(gè)變量進(jìn)行訪問(wèn). 如果沒(méi)有定義寫(xiě)接口, 則該"變量"只讀, 不可寫(xiě).
  • 注意: 必須要先定義@property才能定義寫(xiě)接口.
class Student(object):
    #get接口
    @property
    def score(self):
        return self._score
    #set接口
    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value
>>> s = Student()
>>> s.score = 60 # OK截珍,實(shí)際轉(zhuǎn)化為s.set_score(60)
>>> s.score # OK瓶逃,實(shí)際轉(zhuǎn)化為s.get_score()
60
>>> s.score = 9999
Traceback (most recent call last):
  ...
ValueError: score must between 0 ~ 100!

實(shí)例屬性與類(lèi)屬性的區(qū)別

實(shí)例屬性是在類(lèi)中定義,可以通過(guò)類(lèi)或?qū)嵗L問(wèn)炭分,但如果給實(shí)例綁定一個(gè)同名的屬性,實(shí)例屬性會(huì)把類(lèi)屬性覆蓋掉剑肯。
如下例子中捧毛,當(dāng)調(diào)用s.name = 'Michael'時(shí),s中其實(shí)有兩個(gè)同名的name屬性让网,一個(gè)是類(lèi)屬型("Student")呀忧,一個(gè)是實(shí)例屬性("Michael"),實(shí)例屬性會(huì)將類(lèi)屬性覆蓋掉溃睹,直到它被刪掉而账。

>>> class Student(object):
...     name = 'Student'
...
>>> s = Student() # 創(chuàng)建實(shí)例s
>>> print(s.name) # 打印name屬性,因?yàn)閷?shí)例并沒(méi)有name屬性因篇,所以會(huì)繼續(xù)查找class的name屬性
Student
>>> print(Student.name) # 打印類(lèi)的name屬性
Student
>>> s.name = 'Michael' # 給實(shí)例綁定name屬性
>>> print(s.name) # 由于實(shí)例屬性優(yōu)先級(jí)比類(lèi)屬性高泞辐,因此,它會(huì)屏蔽掉類(lèi)的name屬性
Michael
>>> print(Student.name) # 但是類(lèi)屬性并未消失竞滓,用Student.name仍然可以訪問(wèn)
Student
>>> del s.name # 如果刪除實(shí)例的name屬性
>>> print(s.name) # 再次調(diào)用s.name咐吼,由于實(shí)例的name屬性沒(méi)有找到,類(lèi)的name屬性就顯示出來(lái)了
Student

綁定方法與_slots_

給實(shí)例綁定一個(gè)方法商佑,注意:

  • 綁定實(shí)例方法不能直接進(jìn)行函數(shù)賦值汽烦,因?yàn)樾枰獋魅雽?duì)象實(shí)例。
  • 另外莉御,實(shí)例方法只對(duì)單個(gè)實(shí)例起作用撇吞。
>>> def set_age(self, age): # 定義一個(gè)函數(shù)作為實(shí)例方法
...     self.age = age
...
>>> from types import MethodType
>>> s.set_age = MethodType(set_age, s) # 給實(shí)例綁定一個(gè)方法

給類(lèi)綁定方法:直接賦值,但函數(shù)第一個(gè)參數(shù)必須為self

  • 類(lèi)綁定方法對(duì)所有實(shí)例起作用礁叔,而且不需要重新實(shí)例化牍颈,之前創(chuàng)建的實(shí)例也起作用
>>> def set_score(self, score):
...     self.score = score
...
>>> Student.set_score = set_score

使用_slots_可以限制添加實(shí)例的屬性(包括變量 和方法)

類(lèi)中的特殊函數(shù)

  • _init_:類(lèi)的初始化函數(shù)/構(gòu)造函數(shù)
  • _slot_:限制類(lèi)及其實(shí)例的可添加屬性
  • _len_: 返回長(zhǎng)度,支持len()函數(shù)琅关,它自動(dòng)去調(diào)用該對(duì)象的_len_()方法
  • _str_: print()一個(gè)實(shí)例時(shí)煮岁,會(huì)調(diào)用該函數(shù)
  • _repr_:直接顯示變量調(diào)用該函數(shù)讥蔽,為調(diào)試服務(wù)的
s = Student()
print(s) #調(diào)用__str__
s  #調(diào)用__repr__
  • _iter_: 如果一個(gè)類(lèi)想被用于for ... in循環(huán),類(lèi)似list或tuple那樣画机,就必須實(shí)現(xiàn)一個(gè)_iter_()方法冶伞,該方法返回一個(gè)迭代對(duì)象,然后步氏,Python的for循環(huán)就會(huì)不斷調(diào)用該迭代對(duì)象的_next_()方法拿到循環(huán)的下一個(gè)值响禽,直到遇到StopIteration錯(cuò)誤時(shí)退出循環(huán)。
class Fib(object):
    def __init__(self):
        self.a, self.b = 0, 1 # 初始化兩個(gè)計(jì)數(shù)器a荚醒,b

    def __iter__(self):
        return self # 實(shí)例本身就是迭代對(duì)象芋类,故返回自己

    def __next__(self):
        self.a, self.b = self.b, self.a + self.b # 計(jì)算下一個(gè)值
        if self.a > 100000: # 退出循環(huán)的條件
            raise StopIteration()
        return self.a # 返回下一個(gè)值

>>> for n in Fib():
...     print(n)
...
1
1
2
3
5
...
46368
75025
  • _getitem_: 支持list那樣按照下標(biāo)取出元素
class Fib(object):
    def __getitem__(self, n):
        a, b = 1, 1
        for x in range(n):
            a, b = b, a + b
        return a
>>> f = Fib()
>>> f[0]
1
  • _getattr_: 調(diào)用對(duì)象屬性時(shí),如果找不到某個(gè)屬性界阁,會(huì)調(diào)用該函數(shù)侯繁。
  • _call_: 支持實(shí)例化方法,直接用實(shí)例調(diào)用方法
class Student(object):
    def __init__(self, name):
        self.name = name

    def __call__(self):
        print('My name is %s.' % self.name)
        
>>> s = Student('Michael')
>>> s() # self參數(shù)不要傳入泡躯, 調(diào)用s.__call__()
My name is Michael.

>>> callable(Student())
True

通過(guò)callable()函數(shù)贮竟,我們就可以判斷一個(gè)對(duì)象是否是“可調(diào)用”對(duì)象。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末较剃,一起剝皮案震驚了整個(gè)濱河市咕别,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌重付,老刑警劉巖顷级,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異确垫,居然都是意外死亡弓颈,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)删掀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)翔冀,“玉大人,你說(shuō)我怎么就攤上這事披泪∠俗樱” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵款票,是天一觀的道長(zhǎng)控硼。 經(jīng)常有香客問(wèn)我,道長(zhǎng)艾少,這世上最難降的妖魔是什么卡乾? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮缚够,結(jié)果婚禮上幔妨,老公的妹妹穿的比我還像新娘鹦赎。我一直安慰自己,他們只是感情好误堡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布古话。 她就那樣靜靜地躺著,像睡著了一般锁施。 火紅的嫁衣襯著肌膚如雪陪踩。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天沾谜,我揣著相機(jī)與錄音膊毁,去河邊找鬼胀莹。 笑死基跑,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的描焰。 我是一名探鬼主播媳否,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼荆秦!你這毒婦竟也來(lái)了篱竭?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤步绸,失蹤者是張志新(化名)和其女友劉穎掺逼,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體瓤介,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吕喘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了刑桑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片氯质。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖祠斧,靈堂內(nèi)的尸體忽然破棺而出闻察,到底是詐尸還是另有隱情,我是刑警寧澤琢锋,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布辕漂,位于F島的核電站,受9級(jí)特大地震影響吴超,放射性物質(zhì)發(fā)生泄漏钉嘹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一烛芬、第九天 我趴在偏房一處隱蔽的房頂上張望隧期。 院中可真熱鬧飒责,春花似錦、人聲如沸仆潮。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)性置。三九已至拾并,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鹏浅,已是汗流浹背嗅义。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留隐砸,地道東北人之碗。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像季希,于是被迫代替她去往敵國(guó)和親褪那。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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