日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

带你学python基础:面向对象编程

發(fā)布時間:2025/3/20 python 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 带你学python基础:面向对象编程 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

面向對象編程是個啥呢,其實,在傳統(tǒng)的語言中,比如 C 語言,是不存在面向對象編程這個概念的,那時候的語言只有面向過程編程,也就是我們寫代碼從頭寫到底,最多也就是有函數(shù)。所以,這樣的代碼風格是比較難維護的。

后來,隨著編程語言的改進,在很多的語言都有了面向對象的思想,比如 C++、Java、C#等,而 Python也是如此。

一、那什么是面向對象呢?

拿個簡單的例子說說,比如我們一個人,有頭、身體、腿、手等,這些東西在面向對象的思想中,都可以把他們拆分為一個一個的對象,而不會把人就看做一個對象。

在我們經(jīng)常玩的游戲中,每一個英雄,每一個兵器,都是一個個的對象,每個事物都是對象。

在面向對象編程中,我們還會談到另外一個概念:類。

那么什么是類呢,類是一個抽象的概念,我們知道有動物,動物下面有各種各樣不同的動物,狗,老虎等。所以,類是就是動物,也就是不同類型的動物的總稱,也是抽象。而對象就是具體的類別的動物。

類是對象的類型,具有相同屬性和行為事物的統(tǒng)稱。類是抽象的,在使用的時候通常會找到這個類的一個具體存在。

萬物皆對象,對象擁有自己的特征行為

打個比方,我們每個人都可以看做是一個對象,而我們每個人都有我們自己的不同的特征,同時,我們也會產(chǎn)生我們的各種各樣的行為。

這個圖是不是看了就知道對象的特性了。

相信講了這么多了,我們應該知道什么是類和對象了。下面我們講一下,如何定義類。

二、定義類

首先,我們通過一個案例來說說如何定義類,最后再給出定義類的方法。

# 定義類 class pen():def __init__(self, str, len):self.str = strself.len = len # 實例變量通過init初始化聲明# 定義類變量width = 5'''獲取信息'''def getStr(self):print('str:%s,len:%s' % (self.str, self.len))print('width:', pen.width)pen = pen('初始化', 10) pen.getStr()

上面定義了一個類,這個類名為pen,然后,我們在類中定義了它的特征屬性str和len,同時,我們還定義了一個行為(獲取信息)。

通過這個例子,我們就可以看出怎么定義類的。

定義類規(guī)則

class 類名:屬性列表方法列表

在上面這個例子中,我們發(fā)現(xiàn)這里存在兩種變量,一種是實例屬性,一種是類屬性。下面我們就說說這兩種變量有什么區(qū)別。

  • 類變量:也可以說類屬性,類變量在整個實例化的對象中是公用的。類變量定義在類中且在函數(shù)體之外。類變量通常不作為實例變量使用。如果需要用在函數(shù)中使用類名.類屬性訪問,如例子中的width = 5。
  • 實例變量:也可以說實例屬性,定義在方法中的變量,只作用于當前實例的類, 如例子中的len。

好了,我們知道怎么定義類和定義類變量和實例變量,那么如何訪問這些變量呢?

三、訪問變量

方法

實例對象.屬性

舉例
例如,我們需要訪問上面的pen的變量,則可以使用下面的方式。

# 訪問變量 print(pen.len) print(pen.width) print(pen.str)

當然,你可能會想,還有其他方式嗎,確實,還有其他方式,Python也提供了類似JavaScript的訪問方式。

getattr(obj, name[, default]) #訪問對象的屬性 hasattr(obj,name) # 檢查是否存在一個屬性 setattr(obj,name,value) # 設置一個屬性。如果屬性不存在,會創(chuàng)建一個新屬性 delattr(obj, name) # 刪除屬性

舉例

# -*- coding:utf-8 -*-# 定義類 class pen():def __init__(self, str, len):self.str = strself.len = len # 實例變量通過init初始化聲明# 定義類變量width = 5'''獲取信息'''def getStr(self):print('str:%s,len:%s' % (self.str, self.len))print('width:', pen.width)pen = pen('初始化', 10)# 通過內置方法訪問屬性 print(getattr(pen, 'len')) print(hasattr(pen, 'len'))setattr(pen, 'len', 20) print(pen.len)delattr(pen, 'len') print(pen.len)

內置類屬性

另外,Python本身還提供了自己內置的類屬性,分別有下面這些。

__dict__ : 類的屬性(包含一個字典,由類的屬性名:值組成) 實例化類名.__dict__ __doc__ :類的文檔字符串 (類名.) 實例化類名.__doc__ __name__: 類名,實現(xiàn)方式 類名.__name__ __bases__ : 類的所有父類構成元素(包含了以個由所有父類組成的元組)

舉例
我們還是以上面的例子來講

print(pen.__dict__) #會將實例對象的屬性和值通過字典的形式返回 print(pen.__doc__)

特殊說明

在前面的例子中,我們看到了init和self這兩個關鍵字,下面講解一下。

__init__():是一個特殊的方法屬于類的專有方法,被稱為類的構造函數(shù)或初始化方法,方法的前面和后面都有兩個下劃線。

這是為了避免Python默認方法和普通方法發(fā)生名稱的沖突。每當創(chuàng)建類的實例化對象的時候,__init__()方法都會默認被運行。作用就是初始化已實例化后的對象,這就是構造函數(shù)的意思。

在方法定義中,第一個參數(shù)self是必不可少的。類的方法和普通的函數(shù)的區(qū)別就是self,self并不是Python的關鍵字,你完全可以用其他單詞取代他,只是按照慣例和標準的規(guī)定,推薦使用self。

既然是面向對象編程,那么,接下來肯定要說一下面向對象的三大特性了。

四、面向對象的三大特性

封裝

封裝這個特性,其實在前面就已經(jīng)接觸到了,只是沒有明白的說而已。

封裝字面上的意思就是把東西包裹起來,那么,在面向對象的編程中,其實封裝也就是這個意思,常見的,比如,前面我們說的的類 class,我們把一些對象的屬性和行為包裹在一個類里面,這就是封裝的特性。

繼承

我們都知道,我們有父子關系,很多時候,兒子都會去繼承父親的財產(chǎn)的,好像都是這樣的吧,哈哈。

在面向對象的編程中也是這么個意思,但是不叫父親和兒子,我們把父親叫做父類,兒子稱為子類,我們子類去繼承父類的財產(chǎn),這個就是一個繼承的特性。

那我們如何用 Python 來表達這種關系呢,下面,我們用一個例子先講一下,后面再講規(guī)則。

父親,兒子和女兒的故事

# 定義類 class Father():'''定義一個父親類'''def __init__(self, money, house):self.money = moneyself.house = housedef wealth(self):print('父親給我 %d w, %d 套房子' % (self.money, self.house))class Son(Father):'''定義一個兒子類,繼承自父親類'''def __init__(self, money, house):super().__init__(money, house)class Daughter(Father):'''定義一個女兒類,繼承自父親類'''def __init__(self, money, house):super().__init__(money, house)# 上面定義了一個父親類,一個兒子類,一個女兒類。 # 兒子類和女兒類都繼承自父親類,所以,他們就擁有了父親的財,在編程中也就是擁有了變量和方法。 son = Son(100, 10) daughter = Daughter(200, 5)# 繼承自父親類,所以自己不定義這個wealth方法,也會自動繼承這個方法 son.wealth() daughter.wealth()

通過這個例子,定義了一個父親類,一個兒子類,一個女兒類。

兒子類和女兒類都繼承自父親類,所以,他們就擁有了父親的財,在編程中也就是擁有了變量和方法。

在上面的例子中發(fā)現(xiàn),我們只要在定義類的時候,在括號()中寫上父類的名字,這就是繼承了。

其中,我們也要注意,一個 super() 方法,它的作用是用來繼承父類的屬性。

所以,下面我們就大概知道繼承的規(guī)則怎么寫了。

規(guī)則

class DerivedClassName(Base1, Base2, Base3):<statement-1>...<statement-N>

注意:圓括號中父類的順序,如果繼承的父類中有相同的方法名,而在子類中使用時未指定,python將從左至右查找父類中是否包含方法,在圓括號中有多個類名時,我們稱為:多繼承。也就是說,我們從多個父類繼承了。

好了,繼承我們就說到這里了。下面我們再說說最后一個面向對象的特性:多態(tài)

多態(tài)

在談到多態(tài)時,我們就不得不提到另外一個概念了,這個概念就是重寫。例如,我們的容貌有一些地方是會跟父母很相像的,但是,我們也會有很多我們自己的特點。在面向對象編程里面也是這樣的,我們會繼承父類的特性,但是,在繼承的同時,我們也會發(fā)生改變的,這就是重寫

那么如何實現(xiàn)重寫呢?接著看!

# 定義類 class Father():'''定義一個父親類'''def __init__(self, money, house):self.money = moneyself.house = housedef wealth(self):print('父親給我 %d w, %d 套房子' % (self.money, self.house))def character(self):print('我很高!')class Son(Father):'''定義一個兒子類,繼承自父親類'''def __init__(self, money, house):super().__init__(money, house)def character(self):print('我很胖!')class Daughter(Father):'''定義一個女兒類,繼承自父親類'''def __init__(self, money, house):super().__init__(money, house)def character(self):print('我很瘦!')# 上面定義了一個父親類,一個兒子類,一個女兒類。 # 兒子類和女兒類都繼承自父親類,所以,他們就擁有了父親的財,在編程中也就是擁有了變量和方法。 father = Father(350, 20) son = Son(100, 10) daughter = Daughter(200, 5)# 繼承自父親類,所以自己不定義這個wealth方法,也會自動繼承這個方法 son.wealth() daughter.wealth()# 多態(tài) father.character() son.character() daughter.character()

在繼承的那個例子的基礎上,我們又在父親類中加了一個 character 方法,然后兒子類和女兒類在繼承這個方法的同時,還對這個 character 方法進行了修改。

所以,此時,兒子類和女兒類在調用這兩個方法時,顯示的內容就不一樣了。

也就是說,當子類和父類都存在相同的 character()方法時,子類的 character() 覆蓋了父類的 character(),在代碼運行時,會調用子類的 character()。

這樣,我們就獲得了繼承的另一個好處:多態(tài)

多態(tài)的好處就是,當我們需要傳入更多的子類,例如新增 Teenagers、Adult 等時,我們只需要繼承 Father 類型就可以了,而 character()方法既可以直不重寫(即使用Father的),也可以重寫一個特有的。這就是多態(tài)的意思。調用方只管調用,不管細節(jié),而當我們新增一種Father的子類時,只要確保新方法編寫正確,而不用管原來的代碼。這就是著名的“開閉”原則:

  • 對擴展開放(Open for extension):允許子類重寫方法函數(shù)
  • 對修改封閉(Closed for modification):不重寫,直接繼承父類方法函數(shù)

ok,面向對象的三大特性就講到這里。接下來講講關于類的其他知識!

五、類屬性與實例屬性

我們在前面的幾個例子中,我們發(fā)現(xiàn),在類中我們都定義了一些屬性或者說變量。那什么是類屬性,什么是實例屬性呢?

類屬性是類本身的屬性,該類的實例都能調用,而實例屬性是某個具體的實例特有的屬性,不會影響到類,也不會影響到其他實例。

1.實例屬性

關于實例屬性,我們只要記住下面三點就可以了。

  • 在__init__(self,...)中初始化
  • 內部調用時都需要加上self.
  • 外部調用時用對象名.屬性名調用

2.類屬性

  • 內部用類名.類屬性名調用
  • 外部既可以用類名.類屬性名,又可以用對象名.類屬性名來調用,但是,后者是實例屬性的值

下面我們看一個簡單例子:

# 定義類 class Father():'''定義一個父親類'''age = 40 # 定義一個類屬性def __init__(self, money, house):self.money = money # 實例屬性self.house = housedef wealth(self):print('父親給我 %d w, %d 套房子,類屬性: %d ,實例屬性:%d' % (self.money, self.house, Father.age, self.age))def character(self):print('我很高!')father = Father(350, 20)father.house = 4 # 修改實例變量的值,對象名.屬性 Father.age = 41 # 修改類變量的值:類名.屬性 或 對象名.屬性(但后者修改的值是實例屬性) father.age = 42 father.wealth()

下面,我們再用類屬性實現(xiàn)一個數(shù)值自增

# 定義類 class Father():'''定義一個父親類'''age = 40 # 定義一個類屬性def __init__(self, money, house):self.money = money # 實例屬性self.house = houseFather.age += 1 # 類屬性自增father = Father(350, 20) print(Father.age)father2 = Father(350, 20) print(Father.age)

但是,在類中,我們不能用 self.age 來自增,這樣是不行的,就像在類外不能用對象名.類變量來改變值一樣。

下面,我們用self.age 來自增試試什么效果。

# -*- coding:utf-8 -*-# 定義類 class Father():'''定義一個父親類'''age = 40 # 定義一個類屬性def __init__(self, money, house):self.money = money # 實例屬性self.house = houseself.age += 1 # 類屬性自增father = Father(350, 20) print(Father.age)father2 = Father(350, 20) print(Father.age)

這段代碼就將 Father 改為 self。但輸出結果卻不改變,如下

接下來,我們再深入的分析一下,看類屬性和實例屬性到底有什么聯(lián)系?

# 定義類 class Father():'''定義一個父親類'''age = 40 # 定義一個類屬性def __init__(self, money, house):self.money = money # 實例屬性self.house = housefather1 = Father(350, 20) father2 = Father(350, 20)father1.age += 1 print(father1.age, father2.age, Father.age) Father.age += 1 print(father1.age, father2.age, Father.age) # father2.age 因為這個實例屬性不存在,所以找類屬性為41 Father.age += 1 print(father1.age, father2.age, Father.age)

從這個結果我們可以看出,類屬性自增,實例屬性是不會跟著自增的,實例屬性自增,每個實例屬性之間也是獨立的,但是,當實例屬性不存在時,編譯器是會去找類屬性的值。

所以說,在Python中屬性的查找機制是自下而上的,即首先在實例屬性中查找,如果實例屬性不存在,再到類屬性中查找

六、訪問權限(來自:https://www.cnblogs.com/Lambda721/p/6130213.html)

在Class內部,可以有屬性和方法,而外部代碼可以通過直接調用實例變量的方法來操作數(shù)據(jù),這樣,就隱藏了內部的復雜邏輯。

但是,從前面Student類的定義來看,外部代碼還是可以自由地修改一個實例的name、score屬性:

>>> bart = Student('Bart Simpson', 98) >>> bart.score 98 >>> bart.score = 59 >>> bart.score 59

如果要讓內部屬性不被外部訪問,可以把屬性的名稱前加上兩個下劃線__,在Python中,實例的變量名如果以__開頭,就變成了一個私有變量(private),只有內部可以訪問,外部不能訪問,所以,我們把Student類改一改:

class Student(object):def __init__(self, name, score):self.__name = nameself.__score = scoredef print_score(self):print('%s: %s' % (self.__name, self.__score))

改完后,對于外部代碼來說,沒什么變動,但是已經(jīng)無法從外部訪問實例變量.__name和實例變量.__score了:

>>> bart = Student('Bart Simpson', 98) >>> bart.__name Traceback (most recent call last):File "<stdin>", line 1, in <module> AttributeError: 'Student' object has no attribute '__name'

這樣就確保了外部代碼不能隨意修改對象內部的狀態(tài),這樣通過訪問限制的保護,代碼更加健壯。

但是如果外部代碼要獲取name和score怎么辦?可以給Student類增加get_name和get_score這樣的方法:

class Student(object):...def get_name(self):return self.__namedef get_score(self):return self.__score

如果又要允許外部代碼修改score怎么辦?可以再給Student類增加set_score方法:

class Student(object):...def set_score(self, score):self.__score = score

你也許會問,原先那種直接通過bart.score = 59也可以修改啊,為什么要定義一個方法大費周折?因為在方法中,可以對參數(shù)做檢查,避免傳入無效的參數(shù):

class Student(object):...def set_score(self, score):if 0 <= score <= 100:self.__score = scoreelse:raise ValueError('bad score')

需要注意的是,在Python中,變量名類似__xxx__的,也就是以雙下劃線開頭,并且以雙下劃線結尾的,是特殊變量,特殊變量是可以直接訪問的,不是private變量,所以,不能用__name__、__score__這樣的變量名。

有些時候,你會看到以一個下劃線開頭的實例變量名,比如_name,這樣的實例變量外部是可以訪問的,但是,按照約定俗成的規(guī)定,當你看到這樣的變量時,意思就是,“雖然我可以被訪問,但是,請把我視為私有變量,不要隨意訪問”。

雙下劃線開頭的實例變量是不是一定不能從外部訪問呢?其實也不是。不能直接訪問__name是因為Python解釋器對外把__name變量改成了_Student__name,所以,仍然可以通過_Student__name來訪問__name變量:

>>> bart._Student__name 'Bart Simpson'

但是強烈建議你不要這么干,因為不同版本的Python解釋器可能會把__name改成不同的變量名。

總的來說就是,Python本身沒有任何機制阻止你干壞事,一切全靠自覺。

最后注意下面的這種錯誤寫法:

>>> bart = Student('Bart Simpson', 98) >>> bart.get_name() 'Bart Simpson' >>> bart.__name = 'New Name' # 設置__name變量! >>> bart.__name 'New Name'

表面上看,外部代碼“成功”地設置了__name變量,但實際上這個__name變量和class內部的__name變量不是一個變量!內部的__name變量已經(jīng)被Python解釋器自動改成了_Student__name,而外部代碼給bart新增了一個__name變量。不信試試:

>>> bart.get_name() # get_name()內部返回self.__name 'Bart Simpson'

例子:

#!/usr/bin/env python3 # -*- coding: utf-8 -*-class Student(object):def __init__(self, name, score):self.__name = nameself.__score = scoredef get_name(self):return self.__namedef get_score(self):return self.__scoredef set_score(self, score):if 0 <= score <= 100:self.__score = scoreelse:raise ValueError('bad score')def get_grade(self):if self.__score >= 90:return 'A'elif self.__score >= 60:return 'B'else:return 'C'bart = Student('Bart Simpson', 59) print('bart.get_name() =', bart.get_name()) bart.set_score(60) print('bart.get_score() =', bart.get_score())print('DO NOT use bart._Student__name:', bart._Student__name)

終于到最后一個知識點了,這篇文章寫的真的久!

七、類方法與靜態(tài)方法

這個知識點就說說,因為沒什么好說的。

普通方法我們都知道怎么定義了。

1.普通方法

def fun_name(self,...):pass

2.靜態(tài)方法

  • 通過裝飾器 @staticmethod 裝飾
  • 不能訪問實例屬性
  • 參數(shù)不能傳入self
  • 與類相關但是不依賴類與實例的方法

3.類方法

  • 通過裝飾 @classmethod 修飾
  • 不能訪問實例屬性
  • 參數(shù)必須傳入cls
    必須傳入cls參數(shù)(此類對象和self代表實例對象),并且用此來調用類屬性:cls.類屬性名。

最后,再總結一下。

  • 靜態(tài)方法與類方法都可以通過類或者實例來調用,其兩個的特點都是不能夠調用實例屬性。
  • 靜態(tài)方法不需要接收參數(shù),使用類名.類屬性。

下面,再舉一個例子看看。

# -*- coding:utf-8 -*-# 定義類 class Father():'''定義一個父親類'''age = 40 # 定義一個類屬性def __init__(self, money, house):self.money = money # 實例屬性self.house = house# 創(chuàng)建普通方法def getMoney(self):# 類屬性的使用通過類名.屬性名使用 這是規(guī)范# 私有屬性在類里面使用正常使用print('我有:%d w' % (self.money)) # 在方法里面使用實例屬性# 創(chuàng)建一個靜態(tài)方法@staticmethoddef aa(): # 不需要傳遞實例# 靜態(tài)方法不能訪問實例屬性# 靜態(tài)方法只能訪問類屬性print('我:%d 歲' % Father.age) # 在方法里面使用實例屬性# 類方法@classmethoddef bb(cls, n): # class 也不是關鍵字# 類方法不能訪問實例屬性cls.age = nprint('我:%d 歲' % cls.age) # 就用cls.類屬性father1 = Father(350, 20) father2 = Father(350, 20)# 通過對象來調用靜態(tài)方 father1.aa() # 通過對象來調用類方法 father1.bb(18)# 靜態(tài)方法和類方法的調用,推薦使用類名的方式去調用 # 通過類名來調用靜態(tài)方法 Father.aa() # 通過類名來調用類方法 Father.bb(18)

八、總結

這一節(jié)講了很多,需要好好消化。

總結

以上是生活随笔為你收集整理的带你学python基础:面向对象编程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。