Python 面向?qū)ο缶幊?/h1>

類和對象

定義類

Python支持面向?qū)ο缶幊唐担旅媸且粋€例子夺欲。我們可以看到毯盈,在Python中聲明類和其他語言差不多剃毒。不過實際上差別還是挺大的。

首先搂赋,Python沒有嚴格意義上的構(gòu)造函數(shù)赘阀,只有一個__init__(self,XXX)函數(shù),該函數(shù)和構(gòu)造函數(shù)的功能差不多脑奠,用來初始化對象的狀態(tài)基公。之后創(chuàng)建對象的時候,直接使用類名和參數(shù)列表來創(chuàng)建宋欺,這樣會調(diào)用初始化函數(shù)來創(chuàng)建對象轰豆。

特別要提一點,所有的Python類的實例函數(shù)的第一個參數(shù)必須是self齿诞,這個參數(shù)類似于Java的this關(guān)鍵字酸休,指代當前對象。如果我們調(diào)用類上的方法a.f()祷杈,那么a這個實例就會傳遞給self參數(shù)斑司。

下面介紹一下Python的實例字段。實例字段使用self.XXX來定義但汞。Python不能像Java那樣靜態(tài)的聲明字段宿刮。如果有需要,直接使用self.加字段名即可私蕾,這也是動態(tài)語言的一個特點僵缺。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return f'Person(name:{self.name},age:{self.age})'


person=Person('yitian',24)
print(person)

上面這個例子還定義了一個__str__(self)函數(shù),這個函數(shù)和Java的toString()函數(shù)類似踩叭,當輸出的時候就會自動調(diào)用這個函數(shù)將對象轉(zhuǎn)換為可讀的字符串形式磕潮。Python中還有很多__XXX__形式的慣例函數(shù),肩負著不同的職責容贝。

共享字段和私有字段

首先需要說明自脯,Python中沒有publicprivate這樣的字段訪問修飾符嗤疯,也就是說只要你想冤今,你可以調(diào)用對象上的任意字段和方法闺兢。這里說的都只是一種編碼的契約茂缚,我們在編寫Python類的時候也要遵循這些契約戏罢,才能寫出合格的代碼來。

前面已經(jīng)說了脚囊,實例字段使用self.來訪問龟糕。如果在類中編寫沒有self的變量,那么這些變量就是類變量悔耘,可以在該類的所有對象之間共享讲岁。這個概念類似Java的靜態(tài)字段。下面的population就是一個共享字段的例子衬以。

class Person:
    population = 0

    def __init__(self, name, age):
        self.name = name
        self.age = age
        Person.population += 1

    def __str__(self):
        return f'Person(name:{self.name},age:{self.age})'


yitian = Person('yitian', 24)
zhang3 = Person('zhang3', 25)
print(yitian)
print(f'population:{Person.population}')

最后來說說私有字段缓艳。私有字段慣例上需要添加下劃線_前綴。雖然這些“私有變量”也可以在類外邊訪問看峻,但是我們千萬不要這么做阶淘。私有字段作為類的內(nèi)部實現(xiàn),隨時可能存在變化的可能互妓,不應(yīng)該向外部暴露溪窒。我們的代碼中也不應(yīng)該依賴其他類庫的私有變量。

結(jié)構(gòu)體

有時候我們可能需要結(jié)構(gòu)體或者數(shù)據(jù)類這一概念冯勉,也就是將相關(guān)的變量封裝到一個類中澈蚌。在Python中可以定義一個空類,然后創(chuàng)建對象灼狰,并動態(tài)賦值宛瞄。

print('--------------結(jié)構(gòu)體--------------')


class StudentInfo:
    pass


info = StudentInfo()
info.name = 'yitian'
info.age = 24
info.gender = 'male'

print(f'info({info.name},{info.age},{info.gender})')

繼承

單繼承

支持定義類的語言一般也都支持繼承,不然要這么個功能有什么用伏嗜。如果要繼承某個或某些類坛悉,在類定義上使用括號指定要繼承的基類。如果需要訪問基類的成員承绸,使用基類名加點訪問符.來訪問裸影。

class Student(Person):
    def __init__(self, id, name, age):
        Person.__init__(self, name, age)
        self.id = id

    def __str__(self):
        return f'Student(id:{self.id},name:{self.name},age:{self.age})'

    def introduce_myself(self):
        print(f"I'm {self.name}, I'm {self.age} years old student.")


xiaoming = Student(1, 'xiaoming', 14)
print(xiaoming)
xiaoming.introduce_myself()

繼承層次

按照C++的概念,Python類的所有函數(shù)都是虛的军熏,也就是說在子類中重寫的所有函數(shù)轩猩,都會父類的同名函數(shù)。如果需要調(diào)用父類的版本荡澎,需要使用父類名.XXX的方式來訪問均践。例如,如果我們要訪問xiaoming的父類自我介紹摩幔。就需要使用下面的語句彤委。

# 調(diào)用父類版本
Person.introduce_myself(xiaoming)

Python提供了兩個內(nèi)置函數(shù)isinstanceissubclass來幫我們判斷類的繼承關(guān)系。用法很簡單或衡,下面的結(jié)果依次是:真真真假焦影。

print('--------------繼承關(guān)系--------------')

print(f'xiaoming is Student:{isinstance(xiaoming,Student)}')
print(f'xiaoming is Person:{isinstance(xiaoming,Person)}')
print(f'Student is Person:{issubclass(Student,Person)}')
print(f'Person is Student:{issubclass(Person,Student)}')

多重繼承

最后再來說說多重繼承车遂。多重繼承的類簽名類似下面這樣。當我們訪問子類的成員時斯辰,Python會先查找子類中存不存在該成員舶担。如果不存在的話在查找父類,如果父類不存在就查找父類的父類彬呻,直到查到頭為止衣陶。如果到這時候還沒查找到就會拋出異常。

對于多重繼承的話闸氮,這個過程可以簡單的看成從左到右的剪况、深度優(yōu)先的查找過程:如果子類中不存在該成員,就先從Base1開始查找蒲跨,如果Base1和它的所有父類都沒有拯欧,再從Base2開始查找,以此類推财骨。當然實際情況略微復(fù)雜一點镐作,因為Python會檢查類繼承層次是否存在相同的父類,并確保相同的父類只訪問一次隆箩。

class DerivedClassName(Base1, Base2, Base3):

迭代器和生成器

迭代器

在很多編程語言中都有迭代器的概念该贾,迭代器可以在for-loop循環(huán)中使用。一般情況下迭代器會有next()hasNext()等類似的方法捌臊,確定什么時候應(yīng)該停止迭代杨蛋,什么時候返回元素。

在Python中需要使用__next__(self)函數(shù)來執(zhí)行迭代理澎,如果到了末尾則需要拋出StopIteration異常逞力。如果編寫了__next__(self)函數(shù),我們就可以讓__iter__(self):函數(shù)返回自身糠爬。這樣一個迭代器就寫好了寇荧,我們可以在for循環(huán)等地方使用了。

print('--------------迭代器--------------')


class IterableObj:
    def __init__(self, data):
        self.data = data
        self.index = -1

    def __iter__(self):
        return self

    def __next__(self):
        if self.index == len(self.data) - 1:
            raise StopIteration
        self.index += 1
        return self.data[self.index]


obj1 = IterableObj([1, 2, 3])
for i in obj1:
    print(i, end=' ')
print()

Python還包含了兩個內(nèi)置函數(shù)iter()next()用于創(chuàng)建迭代器和執(zhí)行迭代执隧。下面是使用列表迭代的例子揩抡。

list1 = [1, 2, 3]
iter1 = iter(list1)
e1 = next(iter1)
e2 = next(iter1)
e3 = next(iter1)

print('List:', e1, e2, e3)

生成器

迭代器雖然使用比較簡單,但還是挺麻煩的镀琉。我們可以使用生成器更簡單的創(chuàng)建迭代器峦嗤。生成器其實就是一個函數(shù),不過這個函數(shù)比較特殊屋摔,它不使用return返回結(jié)果烁设,而是使用yield返回一系列值。當我們在循環(huán)中或者使用next()函數(shù)調(diào)用生成器的時候钓试,每次調(diào)用生成器都會使用yield返回一個值装黑。

print('--------------生成器--------------')


def even_generator(data):
    index = 0
    while index < len(data):
        if data[index] % 2 == 0:
            yield data[index]
        index += 1


integer_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

print(f'even_generator:{[i for i in even_generator(integer_list)]}')

從這個例子我們可以看到耙替,生成器確實比迭代器更方便。

生成器表達式

生成器表達式其實和列表解析表達式差不多曹体,只不過列表解析表達式使用方括號,而生成器表達式使用小括號硝烂。另外箕别,生成器表達式返回的是一個生成器,而列表解析表達式返回的是列表滞谢。除此之外串稀,它們在迭代的時候結(jié)果完全相同。

不過狮杨,由于生成器不是一次性生成所有值母截,所以當?shù)男蛄蟹浅4蟮臅r候,最好使用生成器表達式而不是列表解析表達式橄教。

print('--------------生成器表達式--------------')

odd_generator = (i for i in range(1, 11) if i % 2 != 0)

odd_list = [i for i in range(1, 11) if i % 2 != 0]

print(f'generator type:{type(odd_generator)}')
print(f'list type:{type(odd_list)}')

結(jié)果如下清寇。

--------------生成器表達式--------------
generator type:<class 'generator'>
list type:<class 'list'>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者

  • 序言:七十年代末,一起剝皮案震驚了整個濱河市护蝶,隨后出現(xiàn)的幾起案子华烟,更是在濱河造成了極大的恐慌,老刑警劉巖持灰,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盔夜,死亡現(xiàn)場離奇詭異,居然都是意外死亡堤魁,警方通過查閱死者的電腦和手機喂链,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來妥泉,“玉大人椭微,你說我怎么就攤上這事∶ち矗” “怎么了赏表?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長匈仗。 經(jīng)常有香客問我瓢剿,道長,這世上最難降的妖魔是什么悠轩? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任间狂,我火速辦了婚禮,結(jié)果婚禮上火架,老公的妹妹穿的比我還像新娘鉴象。我一直安慰自己忙菠,他們只是感情好,可當我...
    茶點故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布纺弊。 她就那樣靜靜地躺著牛欢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪淆游。 梳的紋絲不亂的頭發(fā)上傍睹,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天,我揣著相機與錄音犹菱,去河邊找鬼拾稳。 笑死,一個胖子當著我的面吹牛腊脱,可吹牛的內(nèi)容都是我干的访得。 我是一名探鬼主播,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼陕凹,長吁一口氣:“原來是場噩夢啊……” “哼悍抑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起杜耙,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤传趾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后泥技,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浆兰,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年珊豹,在試婚紗的時候發(fā)現(xiàn)自己被綠了簸呈。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡店茶,死狀恐怖蜕便,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情贩幻,我是刑警寧澤轿腺,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站丛楚,受9級特大地震影響族壳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜趣些,卻給世界環(huán)境...
    茶點故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一仿荆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦拢操、人聲如沸锦亦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽杠园。三九已至,卻和暖如春舔庶,著一層夾襖步出監(jiān)牢的瞬間抛蚁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工栖茉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人孵延。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓吕漂,卻偏偏與公主長得像,于是被迫代替她去往敵國和親尘应。 傳聞我的和親對象是個殘疾皇子惶凝,可洞房花燭夜當晚...
    茶點故事閱讀 44,974評論 2 355

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