面向對象(object-oriented ;簡稱: OO) 至今尚未統一的概念 我這裏把它定義爲: 按人們 認識客觀世界的系統思惟方式,採用基於對象(實體) 的概念創建模型,模擬客觀世界分析、設 計、實現軟件的辦法。java
面向對象編程(Object Oriented Programming-OOP) 是一種解決軟件複用的設計和編程方法。 這種方法把軟件系統中相近類似的操做邏輯和操做 應用數據、狀態,以類的型式描述出來,以對象實例的形式在軟件系統中複用,以達到提升軟件開發效率的做用。python
面向對象的理解: - 面向對象是一種設計思想 1. 符合人們的思考習慣 2. 把執行者變成指揮者 3. 簡化功能,把複雜的事情簡單化 - 想完成一個事,找具備這樣功能的對象 - 若是能找到,調用這個對象的功能,完成這個事 - 若是找不到,建立具備這樣功能的對象,再調用完成這個事
面向對象有三大特徵: 1. 封裝 2. 繼承 3. 多態
面向對象編程的2個很是重要的概念:類和對象數據庫
對象是面向對象編程的核心,在使用對象的過程當中,爲了將具備共同特徵和行爲的一組對象抽象定義,提出了另一個新的概念——類編程
類就至關於製造飛機時的圖紙,用它來進行建立的飛機就至關於對象設計模式
- 類是對事務的描述,是抽象的。 - 對象是類的具體體現。 - 類對事務的描述:屬性(名詞)和行爲(動詞)
具備相同屬性和行爲事物的統稱安全
某一個具體事物的存在 ,在現實世界中能夠是看得見摸得着的app
小總結:類就是建立對象的模板函數
擁有相同(或者相似)屬性和行爲的對象均可以抽像出一個類測試
類是對事務的描述。 一、屬性 二、行爲 如今呢,要描述汽車這個類。 一、類名 Car 大駝峯命名法 二、屬性 三、行爲(語法與函數同樣,這裏叫方法) run stop 至少有一個參數,名字任意,通常都是self 對象是類的具體體現 建立對象 名字 = 類()
class Car: def run(self): print('汽車奔跑中。。。。。。') def stop(self): print('汽車急剎中。。。。。。') wlhgs = Car() wlhgs.run() wlhgs.stop() bcs = Car() bm7 = Car() ad8 = Car() #每次建立都是新的對象 print(wlhgs,id(wlhgs)) print(bcs,id(bcs)) #雖然每一個對象都有類裏方法,可是實際上是一個方法,地址同樣。 print(id(wlhgs.run)) print(id(bcs.run))
#建立類 class Car: def run(self): print('汽車奔跑中。。。。。。') def stop(self): print('汽車急剎中。。。。。。') def haha(self): print('哈哈。。。。。。。') #建立對象-實例 bmw = Car() #調用/執行實例方法 bmw.run() #爲對象實例設置一個屬性 bmw.color = '黑色' #獲取對象實例的屬性 print('顏色:%s'%(bmw.color)) bmw.brand = '寶馬7系' print('系列:%s'%(bmw.brand)) aodi = Car() #此時aodi對象實例並無color屬性 #print(aodi.color)
在上一小節的demo中,咱們已經給BMW這個對象添加了2個屬性,wheelNum(車的輪胎數量)以及color(車的顏色),試想若是再次建立一個對象的話,確定也須要進行添加屬性,顯然這樣作很費事,那麼有沒有辦法可以在建立對象的時候,就順便把車這個對象的屬性給設置呢?this
在python中相似於這樣格式__名字__()的方法叫作魔法方法 __init___ 做用: 在對象建立的時候爲對象添加屬性--實例屬性 特色: 在建立對象的時候,自動會被調用 self:當前對象實例,哪一個對象調用了這個方法,self就是哪一個對象
class Car: def __init__(self): print('__init__......') self.color = '黑色' self.brand = '哈弗H6' def run(self): print('汽車奔跑中。。。。。。%s,%s'%(self,id(self))) def stop(self): print('汽車急剎中。。。。。。') # #mumaren = Car() #mumaren.run() #print('%s,%s'%(mumaren,id(mumaren))) haval1 = Car() print(haval1.color) print(haval1.brand) haval2 = Car() print(haval2.color) print(haval2.brand)
class Car: def __init__(self,color,brand): print('__init__......') self.color = color self.brand = brand def run(self): print('汽車奔跑中。。。。。。%s,%s'%(self,id(self))) def stop(self): print('汽車急剎中。。。。。。') haval1 = Car('白色','哈弗h7') print(haval1.color) print(haval1.brand) haval2 = Car('銀灰色','哈弗h9') print(haval2.color) print(haval2.brand) #對象是可變類型 haval3 = haval2 haval3.color = '黑色' print(haval2.color)
__str__ 何時調用? 對象轉換成字符串 str(對象) 測試的時候,打印對象的信息 格式: def __str__(self): return 字符串 print打印的時候,默認就將內容轉成字符串
class Car: def __init__(self,color,brand): print('__init__......') self.color = color self.brand = brand def __str__(self): print('__str__......') return 'Car color:%s,brand:%s'%(self.color,self.brand) def run(self): print('汽車奔跑中。。。。。。') def stop(self): print('汽車急剎中。。。。。。') def show(self): print('color:%s,brand:%s'%(self.color,self.brand)) haval1 = Car('白色','哈弗h7') print(haval1) print(id(haval1)) #print(str(haval1)) #haval1.show()
- self表示是當前對象,能夠理解爲本身 - 能夠把self當作C++中類裏面的this指針同樣理解,就是對象自身的意思 - 某個對象調用其方法時,python解釋器會把這個對象做爲第一個參數傳遞給self,因此開發者只須要傳遞後面的參數便可
示例屬性以下:
示例方法以下:
#定義`地瓜`類 class SweetPotato: '這是烤地瓜的類' #定義初始化方法 def __init__(self): self.cookedLevel = 0 self.cookedString = "生的" self.condiments = []
#烤地瓜方法 def cook(self, time): self.cookedLevel += time if self.cookedLevel > 8: self.cookedString = "烤成灰了" elif self.cookedLevel > 5: self.cookedString = "烤好了" elif self.cookedLevel > 3: self.cookedString = "半生不熟" else: self.cookedString = "生的"
mySweetPotato = SweetPotato() print(mySweetPotato.cookedLevel) print(mySweetPotato.cookedString) print(mySweetPotato.condiments)
print("------接下來要進行烤地瓜了-----") mySweetPotato.cook(4) #烤4分鐘 nt(mySweetPotato.cookedLevel) print(mySweetPotato.cookedString)
運行結果爲:
def __str__(self): msg = self.cookedString + " 地瓜" if len(self.condiments) > 0: msg = msg + "(" for temp in self.condiments: msg = msg + temp + ", " msg = msg.strip(", ") msg = msg + ")" return msg def addCondiments(self, condiments): self.condiments.append(condiments)
定義類: 屬性 一、cookedLevel int 0 二、cookedString str '生的' 三、condiments [] [] 方法 一、初始化屬性 __init__ cookedLevel,cookedString,condiments 二、烤地瓜 cook time 三、加調料 addCondiment condiment 四、地瓜的信息 __str__
完整的代碼以下:
class SweetPotato: "這是烤地瓜的類" #定義初始化方法 def __init__(self): self.cookedLevel = 0 self.cookedString = "生的" self.condiments = [] #定製print時的顯示內容 def __str__(self): msg = self.cookedString + " 地瓜" if len(self.condiments) > 0: msg = msg + "(" for temp in self.condiments: msg = msg + temp + ", " msg = msg.strip(", ") msg = msg + ")" return msg #烤地瓜方法 def cook(self, time): self.cookedLevel += time if self.cookedLevel > 8: self.cookedString = "烤成灰了" elif self.cookedLevel > 5: self.cookedString = "烤好了" elif self.cookedLevel > 3: self.cookedString = "半生不熟" else: self.cookedString = "生的" #添加配料 def addCondiments(self, condiments): self.condiments.append(condiments) # 用來進行測試 mySweetPotato = SweetPotato() print("------有了一個地瓜,尚未烤-----") print(mySweetPotato.cookedLevel) print(mySweetPotato.cookedString) print(mySweetPotato.condiments) print("------接下來要進行烤地瓜了-----") print("------地瓜經烤了4分鐘-----") mySweetPotato.cook(4) #烤4分鐘 print(mySweetPotato) print("------地瓜又經烤了3分鐘-----") mySweetPotato.cook(3) #又烤了3分鐘 print(mySweetPotato) print("------接下來要添加配料-番茄醬------") mySweetPotato.addCondiments("番茄醬") print(mySweetPotato) print("------地瓜又經烤了5分鐘-----") mySweetPotato.cook(5) #又烤了5分鐘 print(mySweetPotato) print("------接下來要添加配料-芥末醬------") mySweetPotato.addCondiments("芥末醬") print(mySweetPotato)
運行結果爲:
home類: 屬性 一、面積 方法 二、存放傢俱 bed類: 屬性: 一、面積 二、名字
#定義一個home類 class Home: def __init__(self, area): self.area = area #房間剩餘的可用面積 #self.light = 'on' #燈默認是亮的 self.containsItem = [] def __str__(self): msg = "當前房間可用面積爲:" + str(self.area) if len(self.containsItem) > 0: msg = msg + " 容納的物品有: " for temp in self.containsItem: msg = msg + temp.getName() + ", " msg = msg.strip(", ") return msg #容納物品 def accommodateItem(self,item): #若是可用面積大於物品的佔用面積 needArea = item.getUsedArea() if self.area > needArea: self.containsItem.append(item) self.area -= needArea print("ok:已經存放到房間中") else: print("err:房間可用面積爲:%d,可是當前要存放的物品須要的面積爲%d"%(self.area, needArea)) #定義bed類 class Bed: def __init__(self,area,name = '牀'): self.name = name self.area = area def __str__(self): msg = '牀的面積爲:' + str(self.area) return msg #獲取牀的佔用面積 def getUsedArea(self): return self.area def getName(self): return self.name #建立一個新家對象 newHome = Home(100)#100平米 print(newHome) #建立一個牀對象 newBed = Bed(20) print(newBed) #把牀安放到家裏 newHome.accommodateItem(newBed) print(newHome) #建立一個牀對象 newBed2 = Bed(30,'席夢思') print(newBed2) #把牀安放到家裏 newHome.accommodateItem(newBed2) print(newHome)
若是有一個對象,當須要對其進行修改屬性時,有2種方法
對象名.屬性名 = 數據 ---->直接修改 對象名.方法名() ---->間接修改
爲了更好的保存屬性安全,即不能隨意修改,通常的處理方式爲
將屬性定義爲私有屬性 添加一個能夠調用的方法,供調用
私有化某些敏感的數據屬性,
對外提供可訪問的接口(方法),
這也是一種封裝
在java,C#中,要求:
一、全部的屬性私有化 二、對外提供get,set
python沒要求。
若是某些屬性就是不讓外部訪問,直接__屬性名 私有化 是否提供對外訪問的接口,根據須要。
class Person: def __init__(self): self.__age = 18 def getAge(self): #判斷一些業務邏輯,若是符號要去,給你數據,不符合,不給。 return self.__age; def setAge(self,age): if age<0 or age>120: print('年齡不符合要求。。。。。。') else: self.__age = age laowang = Person() print(laowang.getAge()) laowang.setAge(-40) print(laowang.getAge())
當刪除一個對象時,python解釋器也會默認調用一個方法,這個方法爲__del__()方法
import time class Animal: # 初始化方法 # 建立完對象後會自動被調用 def __init__(self, name): print('__init__方法被調用') self.__name = name #對象在被垃圾回收機制的時候調用這個方法,來釋放資源。除非有特殊要求,通常不要重寫。 #在關閉數據庫鏈接對象的時候,能夠在這裏,釋放資源 def __del__(self): print('__del__......') wangcai = Animal('旺財') xiaoqiang = wangcai del wangcai print('*'*50) del xiaoqiang time.sleep(10) print('over......')
將共性的內容放在父類中,子類只須要關注本身特有的內容
python中全部的內容都是對象,全部的對象都直接或間接繼承了object
在程序中,繼承描述的是事物之間的所屬關係,例如貓和狗都屬於動物,程序中即可以描述爲貓和狗繼承自動物
將共性的內容放在父類中
子類只關注本身特有的內容
擴展性高,代碼更簡潔
# 定義一個父類 class Dog(object): def __init__(self,name,color): self.name = name self.color = color def run(self): print('%s %s run......'%(self.name,self.color)) # 定義一個子類,繼承Dog類 class TaiDi(Dog): def setName(self,name): self.name = name taidi = TaiDi('泰迪','棕色') taidi.run() #泰迪 棕色 run...... taidi.setName('泰迪弟') taidi.run() #泰迪弟 棕色 run......
總結
class Animal(object): def __init__(self, name='動物', color='白色'): self.__name = name self.color = color def __test(self): print(self.__name) print(self.color) def test(self): print(self.__name) print(self.color) class Dog(Animal): def dogTest1(self): #print(self.__name) #不能訪問到父類的私有屬性 print(self.color) def dogTest2(self): #self.__test() #不能訪問父類中的私有方法 self.test() A = Animal() #print(A.__name) #程序出現異常,不能訪問私有屬性 print(A.color) #A.__test() #程序出現異常,不能訪問私有方法 A.test() print("------分割線-----") D = Dog(name = "小花狗", color = "黃色") D.dogTest1() D.dogTest2()
總結
多繼承:這個類繼承了多個父類,是有順序 繼承具備傳遞性 繼承以後,此對象的方法或屬性就增長。 調用的時候,注意是否本身有,或者父類有。
class A(object): def a(self): print('a......') class B: def b(self): self.c() #這裏又調用C()中的c print('b......') class C(A,B): def c(self): print('c......') # #laowang = C() #laowang.a() #laowang.b() #laowang.c() x = C() x.b() #c...... #b...... #獲取父類 print(C.__bases__) #(<class '__main__.A'>, <class '__main__.B'>) print(A.__bases__) #(<class 'object'>,) #列舉,這個類和繼承類的結構。調用方法的順序**(類名.__mro__)** print(C.__mro__) #(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
所謂重寫,就是子類中,有一個和父類相同名字的方法,在子類中的方法會覆蓋掉父類中同名的方法
class A(object): def haha(self): print('haha a......') class B(A): def haha(self): print('哈哈 b......') b = B() b.haha()
class C2: def haha(self): print('haha 2......') class C3: def haha(self): print('haha 3......') class C4(C3,C2): def haha(self): #super().haha() C2.haha(self) print('haha 4......') laowang= C4() laowang.haha() print(C4.__mro__)
class Fu: def __init__(self,name,age): print('fu...%s'%(id(self))) self.name = name self.age = age class Zi(Fu): def __init__(self,name,age,sex): print('zi...%s'%(id(self))) #super().__init__(name,age) #這是方法一 Fu.__init__(self,name,age) #這是方法二 self.sex = sex def show(self): print('%s,%s,%s'%(self.name,self.age,self.sex)) zi = Zi('老王',43,'男') zi.show() print(id(zi))
多態的概念是應用於Java和C#這一類強類型語言中,而Python崇尚「鴨子類型」。
首先Python不支持多態,也不用支持多態,python是一種多態語言,崇尚鴨子類型。
在程序設計中,鴨子類型(英語:duck typing)是動態類型的一種風格。在這種風格中,一個對象有效的語義,不是由繼承自特定的類或實現特定的接口,而是由當前方法和屬性的集合決定。
python既能夠說支持多態,也能夠說不支持多態 一、支持多態 python的弱類型,變量的類型是根據賦值的類型判斷的,值是什麼類型,變量就是什麼類型 這就是多態 二、不支持多態 由於python是弱類型語言,沒有要求類型,不徹底符合多態的定義。
class F1(object): def show(self): print('F1.show') class S1(F1): def show(self): print('S1.show') class S2(F1): def show(self): print('S2.show') def func(obj): obj.show() #print(type(obj)) s1_obj = S1() func(s1_obj) s2_obj = S2() func(s2_obj) f1 = F1() func(f1)
class People(object): name = 'Tom' #公有的類屬性 __age = 12 #私有的類屬性 p = People() print(p.name) #正確 print(People.name) #正確 print(p.__age) #錯誤,不能在類外經過實例對象訪問私有的類屬性 print(People.__age) #錯誤,不能在類外經過類對象訪問私有的類屬性
class People(object): address = '山東' #類屬性 def __init__(self): self.name = 'xiaowang' #實例屬性 self.age = 20 #實例屬性 p = People() p.age =12 #實例屬性 print(p.address) #正確 print(p.name) #正確 print(p.age) #正確 print(People.address) #正確 print(People.name) #錯誤 print(People.age) #錯誤
class People(object): country = 'china' #類屬性 print(People.country) p = People() print(p.country) p.country = 'japan' print(p.country) #實例屬性會屏蔽掉同名的類屬性 print(People.country) del p.country #刪除實例屬性 print(p.country)
總結
實例方法/對象方法,有一個參數,通常叫self 在使用的時候,對象.方法名(實參) self不須要手動傳值,默認將當前對象傳遞過去給self
語法: @classmethod def 方法名(cls,x,y,z...): 語句 調用: 對象名. 類名. cls:類對象 類也是對象,type的對象, 在類方法中,設置的屬性,是類屬性,全部對象共享。 何時用類方法呢? 一、想經過類直接訪問的方法 二、想經過方法來設置或者修改類屬性
class People(object): country = 'china' #類方法,用classmethod來進行修飾 @classmethod def getCountry(cls): return cls.country @classmethod def setCountry(cls,country): cls.country = country p = People() print(p.getCountry()) #china #能夠用過實例對象引用 print(People.getCountry())#china #能夠經過類對象引用 p.setCountry('japan') print(p.getCountry()) #japan
語法: @staticmethod def 名(形參): 語句 實例方法必須至少有一個參數放在第一個,通常叫self 類方法必須至少有一個參數放在第一個,通常叫cls 靜態方法能夠沒有參數,也能夠有參數,可是沒法直接獲取類對象和實例對象 因此通常靜態方法裏的功能,不與對象相關
class Dog: age = 18 def __init__(self,name): self.name = name @staticmethod def show(): print('show.....%s'%(Dog.age)) d = Dog('旺財') d.show() #show.....18 - 靜態方法中不須要額外定義參數 - 所以在靜態方法中引用類屬性的話,必須經過類對象來引用
設計模式六大原則(1):單一職責原則
即一個類只負責一項職責設計模式六大原則(2):里氏替換原則
全部引用基類的地方必須能透明地使用其子類的對象設計模式六大原則(3):依賴倒置原則
高層模塊不該該依賴低層模塊,兩者都應該依賴其抽象;抽象不該該依賴細節;細節應該依賴抽象。設計模式六大原則(4):接口隔離原則
客戶端不該該依賴它不須要的接口;一個類對另外一個類的依賴應該創建在最小的接口上。設計模式六大原則(5):迪米特法則
一個對象應該對其餘對象保持最少的瞭解。儘可能下降類與類之間的耦合。設計模式六大原則(6):開閉原則
一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。
1.建立型模式
主要目的:建立對象
共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
2.結構型模式
主要目的:對象的組成和對象的關係
共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
3.行爲型模式
主要目的:對象的行爲,對象能作什麼
共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。
組成:
實例:
''' 抽象角色(父類):它通常是具體產品繼承的父類或者實現的接口 ''' class Car(object): def move(self): pass def stop(self): pass ''' 具體產品角色(繼承抽象角色):工廠類所建立的對象就是此角色的實例。 ''' class H1(Car): def move(self): print('哈弗h1 move......') def stop(self): print('哈弗h1 stop......') class H9(Car): def move(self): print('哈弗h9 move......') def stop(self): print('哈弗h9 stop......') class H7(Car): def move(self): print('哈弗h7 move......') def stop(self): print('哈弗h7 stop......') class H6(Car): def move(self): print('哈弗h6 move......') def stop(self): print('哈弗h6 stop......') ''' 工廠類角色:這是本模式的核心,含有必定的邏輯判斷,用來建立產品 ''' class CarFactory: @classmethod def createCar(cls,name): car = None if name=='哈弗H1': car = H1() elif name=='哈弗H9': car = H9() elif name=='哈弗H7': car = H7() elif name=='哈弗H6': car = H6() return car ''' 主代碼 ''' name = input('請輸入要購買的車型:') car = CarFactory.createCar(name) if car!=None: car.move() car.stop() else: print('沒有。。。。。。。')
說明:
工廠函數、工廠類對具體的生成環節進行了封裝,這樣有利於代碼的後需擴展,即把功能劃分的更具體,4s店只負責銷售,汽車廠只負責製造
總結:
對象建立比較複雜的時候,能夠考慮使用簡單工廠
''' 抽象角色(父類):它通常是具體產品繼承的父類或者實現的接口 ''' class Car(object): def move(self): pass def stop(self): pass ''' 具體產品角色(繼承抽象角色):工廠類所建立的對象就是此角色的實例。 ''' class H1(Car): def move(self): print('哈弗h1 move......') def stop(self): print('哈弗h1 stop......') class H9(Car): def move(self): print('哈弗h9 move......') def stop(self): print('哈弗h9 stop......') class H7(Car): def move(self): print('哈弗h7 move......') def stop(self): print('哈弗h7 stop......') ''' 抽象工廠類角色 ''' class CarFactory: @classmethod def createCar(cls,name): pass ''' 具體工廠類角色:這是本模式的核心,含有必定的邏輯判斷,用來建立產品 ''' class H1Factory(CarFactory): @classmethod def createCar(cls,name): return H1() class H9Factory(CarFactory): @classmethod def createCar(cls,name): return H9() class H7Factory(CarFactory): @classmethod def createCar(cls,name): return H7() ''' 主代碼 ''' name = input('請輸入要購買的車型:') car = None if name=='哈弗H1': car = H1Factory.createCar(name) elif name=='哈弗H9': car = H9Factory.createCar(name) if car!=None: car.move() car.stop() else: print('沒有。。。。。。。')
總結:
工廠方法模式的優勢和缺點
a1 = A() 建立對象的步驟 一、首先調用__new__獲得一個對象 二、調用__init__爲對象添加屬性 三、將對象賦值給變量
class A(object): def __init__(self): print("這是 init 方法") def __new__(cls): print(id(cls)) print("這是 new 方法") return object.__new__(cls) a1 = A() print(a1) #7214424 #這是 new 方法 #這是 init 方法 #<__main__.A object at 0x0000000000BDEB00> print(id(a1)) #12446464 print(id(A)) #7214424
總結
確保某一個類只有一個實例,並且自行實例化並向整個系統提供這個實例,這個類稱爲單例類,單例模式是一種對象建立型模式。
一、單例模式Singleton 在項目中某些對象,只有一個,能夠一直使用。 若是再次實例化,會很佔資源和時間。 因此,這樣的對象就須要設計成單例模式。 二、原型模式Prototype 能夠實例化多個對象,每一個都是新的,之前設計的類都是原型模式 object.__new__(cls): 表示建立了一個實例對象
class Singleton: #表示對象是否被建立 None:沒有,其它:已經建立 __instance = None def __new__(cls): if cls.__instance == None: cls.__instance = object.__new__(cls) return cls.__instance s1 = Singleton() s2 = Singleton() s3 = Singleton() print(id(s1)) #18342968 print(id(s2)) #18342968 print(id(s3)) #18342968
class Singleton: #表示對象是否被建立 None:沒有,其它:已經建立 __instance = None #表示是否是第一次調用init: True:第一次調用 False:不是第一次調用 __firstInit = True def __init__(self,*args,**kwargs): if Singleton.__firstInit: self.args = args self.kwargs = kwargs Singleton.__firstInit=False def __new__(cls,*args,**kwargs): if cls.__instance == None: cls.__instance = object.__new__(cls) return cls.__instance s1 = Singleton('老王',10,'add','',money=12345) print(id(s1)) #8514472 print(s1.args[0]) #老王 print(s1.args[2]) #add print(s1.kwargs['money'])#12345 s2 = Singleton('旺財') print(id(s2)) #8514472 print(s2.args[0]) #老王 print(s2.args[2]) #add print(s2.kwargs['money'])#12345 s3 = Singleton() print(s3.kwargs['money'])#12345