Python 面向對象編程

類和對象

定義類

Python支持面向對象編程,下面是一個例子。我們可以看到,在Python中聲明類和其他語言差不多。不過實際上差別還是挺大的。

首先,Python沒有嚴格意義上的構造函數,只有一個__init__(self,XXX)函數,該函數和構造函數的功能差不多,用來初始化對象的狀態。之后創建對象的時候,直接使用類名和參數列表來創建,這樣會調用初始化函數來創建對象。

特別要提一點,所有的Python類的實例函數的第一個參數必須是self,這個參數類似于Java的this關鍵字,指代當前對象。如果我們調用類上的方法a.f(),那么a這個實例就會傳遞給self參數。

下面介紹一下Python的實例字段。實例字段使用self.XXX來定義。Python不能像Java那樣靜態的聲明字段。如果有需要,直接使用self.加字段名即可,這也是動態語言的一個特點。

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)函數,這個函數和Java的toString()函數類似,當輸出的時候就會自動調用這個函數將對象轉換為可讀的字符串形式。Python中還有很多__XXX__形式的慣例函數,肩負著不同的職責。

共享字段和私有字段

首先需要說明,Python中沒有publicprivate這樣的字段訪問修飾符,也就是說只要你想,你可以調用對象上的任意字段和方法。這里說的都只是一種編碼的契約,我們在編寫Python類的時候也要遵循這些契約,才能寫出合格的代碼來。

前面已經說了,實例字段使用self.來訪問。如果在類中編寫沒有self的變量,那么這些變量就是類變量,可以在該類的所有對象之間共享。這個概念類似Java的靜態字段。下面的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}')

最后來說說私有字段。私有字段慣例上需要添加下劃線_前綴。雖然這些“私有變量”也可以在類外邊訪問,但是我們千萬不要這么做。私有字段作為類的內部實現,隨時可能存在變化的可能,不應該向外部暴露。我們的代碼中也不應該依賴其他類庫的私有變量。

結構體

有時候我們可能需要結構體或者數據類這一概念,也就是將相關的變量封裝到一個類中。在Python中可以定義一個空類,然后創建對象,并動態賦值。

print('--------------結構體--------------')


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類的所有函數都是虛的,也就是說在子類中重寫的所有函數,都會父類的同名函數。如果需要調用父類的版本,需要使用父類名.XXX的方式來訪問。例如,如果我們要訪問xiaoming的父類自我介紹。就需要使用下面的語句。

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

Python提供了兩個內置函數isinstanceissubclass來幫我們判斷類的繼承關系。用法很簡單,下面的結果依次是:真真真假。

print('--------------繼承關系--------------')

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會先查找子類中存不存在該成員。如果不存在的話在查找父類,如果父類不存在就查找父類的父類,直到查到頭為止。如果到這時候還沒查找到就會拋出異常。

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

class DerivedClassName(Base1, Base2, Base3):

迭代器和生成器

迭代器

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

在Python中需要使用__next__(self)函數來執行迭代,如果到了末尾則需要拋出StopIteration異常。如果編寫了__next__(self)函數,我們就可以讓__iter__(self):函數返回自身。這樣一個迭代器就寫好了,我們可以在for循環等地方使用了。

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還包含了兩個內置函數iter()next()用于創建迭代器和執行迭代。下面是使用列表迭代的例子。

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

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

生成器

迭代器雖然使用比較簡單,但還是挺麻煩的。我們可以使用生成器更簡單的創建迭代器。生成器其實就是一個函數,不過這個函數比較特殊,它不使用return返回結果,而是使用yield返回一系列值。當我們在循環中或者使用next()函數調用生成器的時候,每次調用生成器都會使用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)]}')

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

生成器表達式

生成器表達式其實和列表解析表達式差不多,只不過列表解析表達式使用方括號,而生成器表達式使用小括號。另外,生成器表達式返回的是一個生成器,而列表解析表達式返回的是列表。除此之外,它們在迭代的時候結果完全相同。

不過,由于生成器不是一次性生成所有值,所以當迭代的序列非常大的時候,最好使用生成器表達式而不是列表解析表達式。

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)}')

結果如下。

--------------生成器表達式--------------
generator type:<class 'generator'>
list type:<class 'list'>
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,619評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,155評論 3 425
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,635評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,539評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,255評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,646評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,655評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,838評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,399評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,146評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,338評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,893評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,565評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,983評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,257評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,059評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,296評論 2 376

推薦閱讀更多精彩內容

  • 面向對象編程 python中一切皆為對象,所謂對象:人是一個對象,電腦是一個對象 我們通過描述屬性(特征)和行為來...
    b485c88ab697閱讀 581評論 0 0
  • 類與實例 類與實例相互關聯著:類是對象的定義,而實例是“真正的實物”,它存放了類中所定義的對象的具體信息。 下面的...
    邪惡的Sheldon閱讀 342評論 0 0
  • 類相關知識 對象相關知識 類屬性增刪改查 實例屬性增刪改查 對象與實例屬性 靜態屬性 類方法 靜態方法 組合 繼承...
    Techml閱讀 417評論 0 0
  • 面向對象編程 面向對象編程——Object Oriented Programming,簡稱OOP,是一種程序設計思...
    蝴蝶蘭玫瑰閱讀 611評論 0 1
  • 面向對象編程——Object Oriented Programming,簡稱OOP,是一種程序設計思想。OOP把對...
    勤快的樹懶閱讀 876評論 1 0