python面向对象生动讲解_Python面向对象语法精讲
本專題的內容結構:
第一部分主要是:面向對象基礎
第二部分主要是:面向對象進階
第一部分的結構:
unit1:面向對象編程模式:
(1),面向對象編程思想
(2),面向對象的三個特征
(3),Python面向對象術語
unit2:Python類的構建:
(1),類的基本構建
(2),類的屬性和方法
(3),類的構造函數和析構函數
unit3:實例1:銀行ATM等待時間分析
(1),對象的設計和構建
(2),生活現象的程序分析
unit4:Python類的封裝
(1),私有屬性和公開屬性
(2),私有方法和公開方法
(3),保留屬性和保留方法
unit5:Python類的繼承:
(1),子類,父類與超類
(2),類的方法重載和屬性重載
(3),類的多繼承
第二部分的結構:
unit1:Python類的運算:
(1),運算符的理解
(2),各類運算符的重載
unit2:Python類的多態:
(1),多態的理解
(2),參數類型的多態
(3),參數形式的多態
unit3:實例2:圖像的四則運算
(1),PIL庫和Numpy 庫實踐
(2),圖像的加減乘除操作
unit4:Python對象的引用
(1),引用的理解
(2),淺拷貝和深拷貝
unit5:Python類的高級話題:
(1),類的特殊裝飾器
(2),命名空間的理解
(3),類的名稱修飾
第一部分的內容:
unit1:面向對象編程模式:
(1),萬物皆對象:
自然意義上的對象:獨立的存在 或 作為目標的事物
>獨立性:對象都存在清晰的邊界,重點在于劃分邊界
>功能性:對象都能表現出一些功能,操作或行為
>交互性:對象之間存在交互,如:運算和繼承
Python語言的“萬物皆對象”:
>Python語言中所有數據類型都是對象,函數是對象,模塊是對象
>Python所有類都是繼承于最基礎類object
>Python語言中數據類型的操作功能都是類方法的體現
(2),面向對象編程思想:
OOP :Object-Oriented Programming
>OOP :面向對象編程,一種編程思想,重點在于高抽象的 復用代碼
>OOP 把對象當做程序的基本單元,對象包含數據和操作數據的函數
>OOP 本質是把問題解決抽象為以對象為中心的計算機程序
注:
>OOP在較大規模或復雜項目中十分有用,OOP可以提高協作產量
>OOP最主要的價值在于代碼復用
>OOP只是一種編程方式,并非解決問題的高級方法
面向過程 vs 面向對象
>面向過程:以解決問題的過程步驟為核心編寫程序的方式
>面向對象:以問題對象構建和應用為核心編寫程序的方式
>所有OOP能解決的問題,面向過程都能解決
小例子:
(3),面向對象的三個特征:
OOP的三個特征:
>封裝:屬性和方法的抽象,用數據和操作數據的方法來形成對象邏輯
>繼承:代碼復用的高級抽象,用對象之間的繼承關系來形成代碼復用
>多態:方法靈活性的抽象,讓對象的操作更加靈活,更多復用代碼
它能讓更少的對象名稱來支持更多的對象操作
它們都是表達了代碼抽象和代碼復用,
封裝的理解:
封裝Encapsulation:屬性和方法的抽象
>屬性的抽象:對類的屬性(變量)進行定義,隔離及保護
>方法的抽象:對類的方法(函數)進行定義,隔離及保護
>目標是形成一個類/對象 對外可操作屬性和方法的接口
繼承的理解:
繼承 Inheritance:代碼復用的高級抽象
>繼承是面向對象程序設計精髓之一
>實現了以類為單位的高抽象級別代碼復用
>繼承是新定義的類 能夠幾乎完全使用原有類屬性和方法的過程
多態的理解:
多態 Polymorphism :僅針對方法,方法靈活性的抽象
>參數類型的多態:一個方法能夠處理多個類型的能力
>參數形式的多態:一個方法能夠接受多個參數的能力
>多態是 OOP的一個傳統概念,Python天然支持多態,不需要特殊語法
其他語言中要用特定的語法用多態,但是Python中設計的弱類型天然支持多態
對多態的理解重點是概念和思路上的理解,更能理解Python對類的方法靈活性的抽象是如何表達的,
(4),Python面向對象術語:
先簡要過一遍,后會介紹:
類 Class 和 對象 Object :
>類:邏輯抽象和產生對象的模板,一組變量和函數的特定編排
>對象:具體表達數據及操作的實體,相當于程序中的"變量"
>實例化:從類到對象的過程,所有"對象"都源于某個"類"
對象: 對象具體分為: 類對象和實例對象
類對象 vs 實例對象 :
>類對象:Class Object,當一個類建立之后,系統會維護個Python類基本信息的數據結構
>實例對象:Instance Object,Python類實例后產生的對象,簡稱:對象
>這是一組概念,類對象全局只有一個(保存類的基本信息),實例對象可以生成多個
屬性: 存儲數據的“變量”,分為 :類屬性 和實例屬性
方法: 操作數據的"函數",
包括:類方法,實例方法,自由方法,靜態方法,保留方法
三個特性:封裝繼承多態
繼承:基類,派生類,子類,父類,超類,重載
命名空間:程序元素作用域的表達
構造和析構:生成對象和刪除對象的過程
(5),Python面向對象實例入門:
是上面的那個例子,計算價格的和,
出現新的保留字class
它可以定義抽象的Product 類,
1 classProduct():2 def __init__(self,name):3 self.name =name4 self.label_price =05 self.real_price =06
7 c = Product("電腦")8 d = Product("打印機")9 e = Product("投影儀")10 c.label_price,c.real_price = 10000,8000
11 d.label_price,d.real_price = 2000,1000
12 e.label_price,e.real_price = 1500,900
13 s1 ,s2 =0,014 for i in[c,d,e]:15 s1+=i.label_price16 s2+=i.real_price17 print(s1,s2)
View Code
unit2:Python類的構建:
python類的構建需要關注的地方:
就是上面的那個圖:它包含了構建一個類所要關注的方方面面:
(1),類的基本構建:
使用class保留字定義類:
class <類名>:
[可以寫個類描述字符串"documentation string"]
<語句塊>
注:類定義不限位置,可以包含在分支或其他從屬語句塊中,執行時存在即可
可以放在全局部分,也可以放在分支,函數,等從屬語句塊中,由于Python語言是腳本語言,
所以在某個對象引用之前,只要是類被定義就可以。
類構造之類的名字:可以是任意有效標識符,建議采用大寫單詞的組合
如:ClassName ,BasicAuto ,BasicCreature
類構造之類描述:在類的定義后首行,以獨立字符串形式定義
定義可以通過<類名>.__doc__屬性來訪問
注:像這種前后都有兩個下劃線的屬性是Python給類保留的屬性,
class DemoClass:
"This is a demo for Python class"
pass
print(DemoClass.__doc__)
>>>This is a demo for Python class
介紹一個概念:類對象
大家不要把類和對象拆開,類對象是一個名詞,(Class Object)
>類定義完成后,默認生成一個類對象
與其他語言不同,python的類只要定義完就會生成一個對象,但這個對象呢?只是與這個類唯一對應的,
每一個類只唯一對應一個類對象,這個類對象是存儲這個類的基本信息的
>每個類唯一對應一個類對象,用于存儲這個類的基本信息
>類對象是type類的實例,表達為type類型
什么是type類型呢?
它是編譯器提供了一種類型,
class DemoClass:
"This is a demo for Python class"
print("hello DemoClass")
print(type(DemoClass))
輸出:
hello DemoClass
我們發現,我們只是定義了這個類,但是它也執行print("hello DemoClass)
這時因為在python中只要這個類被定義了, 就會生成一個表達它信息的 類對象
這個類對象是內置包含在類的定義中的,
那么這個類對象的生成使得類定義中的一些語句被執行,
因此,我們一般不在類的定義中直接包含語句,而是通過屬性和方法來增加操作功能
類對象并不是使用類的常用方式,
使用類的方式最常用的是:通過創建實例對象來使用類的功能
<對象名> = <類名>([<參數>])
進一步采用<對象名>.<屬性名>和<對象名>.<方法名>()體現類的功能
實例對象的類型:
它所生成時的那個類的類型
class DemoClass:
"This is a demo for Python class"
pass
print(type(DemoClass))
cn = DemoClass()
print(type(cn))
輸出:
所以,實例對象和類對象是不一樣的 ,
實例對象是最常用的方式,
了解Python類的構造函數
>類的構造函數用于從類創建實例對象的過程
>類的構造函數為實例對象創建提供了參數輸入方式
>類的構造函數為實例屬性的定義和賦值提供了支持
了解Python類的屬性和方法:
>類的屬性:類中定義的變量,采用描述類的一些特性參數
>類的方法:類中定義且與類相關的函數,用來給出類的操作功能
>屬性和方法是類對外交互所提供的兩種接口方式
(2),類的構造函數:
類的構造函數是從類生成實例對象所使用的函數,
Python中使用預定義的__init__()作為構造函數,
clsaa <類名>:
def __init__(self,<參數列表>)
<語句塊>
類實例化時所使用的函數,可以接收參數并完成初始化操作
class DemoClass:
def __init__(self,name):
print(name)
dc1 = DemoClass("老王")
dc2 = DemoClass("老李")
輸出:
老王
老李
注:通過構造函數__init__()可以為Python對象提供參數
還有,構造函數默認有個參數self ,它內部使用的,默認保留的,
__init__()的使用說明:
>參數:第一個參數約定是self,表示類實例自身,其他參數都是實例參數
>函數名:Python解釋器內部定義的,由雙下劃線開始和結束
>返回值:構造函數沒有返回值,或返回None ,否則產生TypeError異常
self在類定義內部代表類的實例
>self是Python面向對象中約定的一個類參數
>self代表類的實例,在類內部,self用于組合訪問實例相關的屬性和方法
>相比較而言,類名代表類對象本身
(3),類的屬性:
屬性是類內部定義的變量
>類屬性:類對象的屬性,由所有實例對象共享
>實例屬性:實例對象的屬性,由各實例所獨享
類的屬性和實例屬性是如何定義的?
我們知道屬性是變量,類中有兩個地方可以放變量,
第一個是在class的全局命名空間:
<類屬性名> =<類屬性初值>
第二個是在函數/方法中定義的它就是實例屬性:
class <類名>:
<類屬性名>=<類屬性初值>
def __init__(self,<參數列表>):
self.<實例屬性名> = <實例屬性初值>
...
class DemoClass:
count = 0 #直接在類中定義或賦值 無論在類內類外,訪問類屬性都要用<類名>.<屬性名>來訪問
def __init__(self,name,age):
self.name = name
self.age = age
DemoClass.count +=1
dc1 = DemoClass("老王",45)
dc2 = DemoClass("老李",51)
print("總數:",DemoClass.count)
print(dc1.name,dc2.name)
我們已經知道,類屬性在類內,類外都是<類名>.<類屬性>
而對于實例屬性:
在類內部,用self.<屬性名>訪問
在類外部,用<對象名>.<屬性名>訪問
注:在類外,類屬性也是可以用<對象名>.<屬性名>來訪問的
class DemoClass:
def __init__(self,name):
self.name = name
#注:構造函數沒有返回值
def luckey(self):
s = 0
for c in self.name:
s+=ord(c)%100
return s
dc1 = DemoClass("Wang")
dc2 = DemoClass("Li")
print(DemoClass.__dict__) #類對象的屬性字典
print(dc1.__dict__) #實例對象的屬性字典
print(dc2.__dict__) #實例對象的屬性字典
print(DemoClass.__dir__(DemoClass)) #類對象的屬性列表
print(dc1.__dir__()) #實例對象的屬性列表
(4),類的方法:
方法是類內部定義的函數:
>實例方法:實例對象的方法,由各實例對象獨享,最常用的形式
>類方法:類對象的方法,由所有實例對象共享
>自由方法:類中的一個普通函數,由類所在命名空間管理,類對象獨享
>靜態方法:類中的一個普通函數,由類對象和實例對象共享
>保留方法:由雙下劃線開始和結束的方法,保留使用,如__len__()
方法1:實例方法:
實例方法是類內部定義的函數,與實例對象相關
class <類名>:
def <方法名>(self,<參數列表>):
...
實例方法采用<對象名>.<方法名>(<參數列表>)方式使用
class DemoClass:
def __init__(self,name):
self.name = name
#注:構造函數沒有返回值
def luckey(self):
s = 0
for c in self.name:
s+=ord(c)%100
return s
dc1 = DemoClass("Wang")
dc2 = DemoClass("Li")
print(dc1.name,"'s lucky number is :",dc1.luckey())
print(dc2.name,"'s lucky number is :",dc2.luckey())
輸出:
Wang 's lucky number is : 197
Li 's lucky number is : 81
方法2:類方法:
類方法是與類對象相關的函數,由所有實例對象共享
class <類名>:
@classmethod裝飾器
def <方法名>(cls,<參數列表>):
...
類方法采用<類名>.<方法名>(<參數列表>)或<對象名>.<方法名>(<參數列表>)方式使用
>類方法至少包含一個參數,表示類對象,建議使用cls
>@classmethod是裝飾器,類方法定義必須要有
>類方法只能操作類屬性和其他類方法,不能操作實例屬性和實例方法
class DemoClass:
count =0
def __init__(self,name):
self.name = name
DemoClass.count +=1
#注:構造函數沒有返回值
@classmethod
def getChrCount(cls):
s = "0123456789"
return s[DemoClass.count]
dc1 = DemoClass("Wang")
dc2 = DemoClass("Li")
print(DemoClass.getChrCount())
print(dc1.getChrCount()) #類方法是可以被實例對象調用的,因為它歸類對象和實例對象共同所有
輸出:
2
2
方法3,自由方法:
是定義在類命名空間中的普通函數
class <類名>:
def <方法名>(<參數列表>):
...
#注:這里既沒有self,也沒有cls
自由方法采用<類名>.<方法名>(<參數列表>)方式使用,這時的<類名>代表的是命名空間
換句話說,自有方法是什么,它是在<類名>這個命名空間中定義的一個函數,訪問它只能用
<函數名>.方法名來訪問,
注:類對象自己獨有
>自由方法不需要self,cls這類參數,可以沒有參數
>自由方法只能操作類屬性和類方法,不能操作實例屬性和實例方法
>自由方法的使用只能用<類名>
嚴格來說,自由方法就不應該算是方法,它就是個函數,只不過是定義在類的命名空間中
為了統一說法,所以我們叫它自由方法,
class DemoClass:
count =0
def __init__(self,name):
self.name = name
DemoClass.count +=1
#注:構造函數沒有返回值
def func():
DemoClass.count *=100
return DemoClass.count
dc1 = DemoClass("Wang")
print(DemoClass.func())
輸出:100
方法4:靜態方法:
我們知道,自由方法只能由類對象來使用,有沒有辦法讓實例對象使用普通的函數(沒有self,cls)呢?
可以,就是在自由方法的基礎上加上一個裝飾器@classmethod就可以了,
它是定義在類中的普通函數,能夠被所有實例對象共享
class <類名>:
@staticmethod
def <方法名>(<參數列表>):
...
靜態方法采用<類名>.<方法名>(<參數列表>)或<對象名>.<方法名>(<參數列表>)方式使用
>靜態方法可以沒有參數,可以理解為定義在類中的普通函數
>@staticmethod是裝飾器,靜態方法必須用它
>靜態方法只能操作 類屬性和其他類 方法,不能操作實例屬性和實例方法
>相比于自由方法,靜態方法能夠使用<類名>和<對象名>兩種方式調用
class DemoClass:
count =0
def __init__(self,name):
self.name = name
DemoClass.count +=1
#注:構造函數沒有返回值
@staticmethod
def func():
DemoClass.count *=100
return DemoClass.count
dc1 = DemoClass("Wang")
print(dc1.func())
print(DemoClass.func())
記時,方法3和方法4一起記
方法5:保留方法:
保留方法由雙下劃線開始和結束的方法,保留使用
class <類名>:
def <保留方法名>(self,<參數列表>):
...
保留方法一般都對應類的某種操作,使用操作符調用它
其實構造函數本身也是保留方法,
class DemoClass:
count =0
def __init__(self,name):
self.name = name
DemoClass.count +=1
#注:構造函數沒有返回值
def __len__(self):
return len(self.name)
dc1 = DemoClass("Wang")
print(len(dc1))
輸出:4
__len__ ()方法對應內置函數len()函數操作
理解:
這時Python解釋器保留方法,已經對應,只需要編寫代碼即可
重寫保留方法:
class DemoClass:
count =0
def __init__(self,name):
self.name = name
DemoClass.count +=1
#注:構造函數沒有返回值
def __len__(self):
return 5
dc1 = DemoClass("Wang")
print(len(dc1))
輸出:5
終結總結:
我們可以理解為len()只能計算基本數據類型的長度,對于類的長度它不能計算
我們就讓他去調用類的保留方法__len__()
len(dc1)其實它還是調用的是dc1.__len__()方法
然后:這個保留方法內部計算了一個基礎類型的長度len(name)
(5),類的析構函數:
當一個對象不用的時候,我們要對它釋放空間,
Python使用預定義的__del__()作為析構函數
class <類名>:
def __del__(self):
<語句塊>
...
析構函數在“真實” 刪除實例對象時被調用
“真實”后面會介紹
例子:
class DemoClass:
def __init__(self,name):
self.name = name
def __del__(self):
print("再見",self.name)
dc1 = DemoClass("Wang")
del dc1
輸出:
再見Wang
刪除對象就是使用保留字del
使用del刪除對象且對象被真實刪除 時調用析構函數__del__()
>函數名和參數:Python解釋器內部約定,保留方法
>調用條件:當實例對象被“真實刪除”時,才調用該函數語句
>“真實刪除”:當前對象的引用數為0或當前程序退出(垃圾回收)
例子:
import time
class DemoClass:
def __init__(self,name):
self.name = name
def __del__(self):
print("再見",self.name)
dc1 = DemoClass("Wang")
dc2 = dc1 #引用
del dc1
print(dc2.name)
while(True):
time.sleep(1) #使程序不退出
輸出:
Wang
這就是只有當真實刪除時才會調用析構函數
當然,一般構建對象的時候,我們不用寫析構函數,python的垃圾回收機制已經很靈活了。
Python類的內存管理:
>在刪除對象前,Python解釋器會檢查引用次數
>檢查刪除之后是否引用次數為0,不為0則僅刪除當前引用;為0,則刪除對象
>如果程序退出,則由垃圾回收機制刪除對象
那么如何對一個對象的引用數量進行獲取呢?
python提供了一個sys.getrefcount(<對象名>)獲得對象的引用次數
>返回對象引用次數的方法,輔助刪除對象時的分析
>sys.getrefcount()函數返回值為 被 引用值+1
>非特定目的,不建議自己寫析構函數,利用Python垃圾回收機制就行
import sys
class DemoClass:
def __init__(self,name):
self.name = name
def __del__(self):
print("再見",self.name)
dc1 = DemoClass("Wang")
dc2 = dc1 #引用
print(sys.getrefcount(dc1))
輸出:3 (比真實多1)
unit3:實例1:銀行ATM等待時間分析:
需求分析:
可擴展為泊松分布:
1 importrandom as rd2 '''
3 整體思路:4 1,需要一個全局時間5 2,以ATM每次處理結束的時間為時間驅動事件6 3,需要一個等待隊列,維護客戶到達時間7 4,時間變化時,驅動等待隊列變化8 '''
9 classATM():10 def __init__(self,maxtime = 5):11 self.t_max =maxtime12 def getServCompleteTime(self,start= 0):#完成一次業務的時間 start 可賦值給真實的時間,
13 #這樣就是絕對的時間了
14 return start + rd.randint(1,self.t_max)15
16 classCustomers():17 def __init__(self,n):18 self.count =n19 self.left =n20 def getNextArrvTime(self,start = 0,arrvtime = 10): #下一個人到達的時間
21 if self.left !=0:22 self.left -=1
23 return start +rd.randint(1,arrvtime)24 else:25 return026 def isOver(self): #判斷n 個客戶是否都到達了
27 return True if self.left == 0 elseFalse28
29 c = Customers(100) #100個客戶
30 a =ATM()31 wait_list =[] #存放用戶到達時間
32 wait_time =0 #總共等待時間
33 cur_time= 0 #當前時間
34 cur_time +=c.getNextArrvTime()35 wait_list.append(cur_time)36 while len(wait_list) !=0 or notc.isOver():37 if wait_list[0] <= cur_time: #用戶提前到了
38 next_time = a.getServCompleteTime(cur_time) #下次時間
39 delwait_list[0]40 else:41 next_time = cur_time +1
42
43 if not c.isOver() and len(wait_list) ==0:44 next_arrv =c.getNextArrvTime(cur_time)45 wait_list.append(next_arrv)46
47 if not c.isOver() and wait_list[-1]
<
<<
<
<
<<
<
<<<<
<
<<
<
<<
<
<<
<
<<
<<<<
<
<<
<
<
<
<
<<
<
<
<<
<<
<<
<<<
<
<
<
<<&
<
&other
<<
<
<<
<<<<<
<<
<
<
<
<<
<
<
<
總結
以上是生活随笔為你收集整理的python面向对象生动讲解_Python面向对象语法精讲的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python3.7.3 离线安装para
- 下一篇: git查看 对比未提交_30分钟让你掌握