Linux---python中的封裝(內建方法,初始化方法),繼承
面向物件中:哪一個物件呼叫的方法,self就是哪一個物件的引用
在類封裝的方法內部,self就表示當前呼叫方法的物件自己 呼叫方法時,程式設計師不需要傳遞self引數(但是定義的時候,第一個引數必須是self) 在方法內部:可以通過self.訪問物件的屬性 在方法內部:可以通過self.呼叫其他的物件方法 class Cat: def eat(self): print '%s愛吃魚' %self.name def drink(self): print '小貓要喝水' # 建立貓物件 tom = Cat() # 可以使用 .屬性名 利用賦值語句就可以了 tom.name = 'Tom'
tom.eat()
tom.drink()
###內建方法### __del__方法:物件被從記憶體中銷燬前,會自動呼叫 __str__方法:返回物件的描述資訊 print 物件
__del__方法:
在python中 當一個物件被從記憶體中銷燬前(把這個物件從記憶體中刪除掉),會自動呼叫__del__方法 應用場景 __del__如果希望在物件被銷燬前,再做一些事情,可以考慮一下__del__方法
__str__方法: 在python中,使用python輸出物件變數,預設情況下,會輸出這個變數引用的物件是由哪>一個類建立的物件,以及在記憶體中的地址(十六進位制表示) 如果在開發中,希望使用print輸出物件變數時,能夠列印自定義的內容,就可以利用__str__這個內建方法了 class Cat: def __init__(self,new_name): ##__init__ 是python物件的內建方法 self.name = new_name print '%s 來了' %self.name def __del__(self): print '%s 走了' %self.name def __str__(self): ##返回物件的描述資訊 print 物件 # 必須返回一個字串 return '我是 %s' %self.name
# tom是一個全域性變數 # 所以當我們的程式碼全部執行完之後,系統才會把tom這個物件進行回收 tom = Cat('Tom') print tom # print tom.name
# # del關鍵字,可以從記憶體中刪除一個物件,del關鍵字自己呼叫了__del__方法
# del tom
# print '*' * 50
""" 生命週期 一個物件從呼叫類名()建立,宣告週期開始 一個物件的__del__方法一旦被呼叫,生命週期就結束 在物件的生命週期內,可以訪問物件的屬性,呼叫物件的方法 """
###初始化方法### 初始化方法:__init__ 是python物件的內建方法 __init__方法是專門用來定義一個類具有哪些屬性和方法的
初始化方法 我們現在已經知道了使用 類名() 就可以建立一個物件 當使用類名()建立物件時,python的直譯器會自動執行以下操作: 1.為物件在記憶體中分配空間--建立物件 2.呼叫初始化方法為物件的屬性設定初始值--初始化方法(__init__) 這個初始化方法就是__init__方法,__init__是物件的內建方法 __init__方法是專門用來定義一個類具有哪些屬性的方法
class Cat: def __init__(self,new_name): # 與函式一樣 print '這是一個初始化方法' # self.屬性名= 屬性的初始值 #self.name = 'Tom' self.name = new_name # 在類中 任何方法都可以使用這個self.name def eat(self): print '%s 愛吃魚' %self.name # 並沒有呼叫__init__方法 # 使用類名()建立物件的時候,會自動呼叫初始化方法__init__ tom = Cat('Tom') # 在__init__方法的內部使用 self.屬性名= 屬性的初始值 定義物件的屬性 # 定義屬性之後,再使用Cat類建立物件,都會擁有該屬性 print tom.name tom.eat()
lazy_cat=Cat('Lazy_cat') lazy_cat.eat()
###私有屬性和私有方法### 私有屬性和私有方法 應用場景及定義方式 應用場景 在實際開發中,物件的某些屬性或方法可能只希望在物件的內部使用,而不希望在外部被訪問到 私有屬性 就是 物件 不希望公開的 屬性 私有方法 就是 方法 不希望公開的 方法 定義方法 在定義屬性或方法時,在屬性名或者方法名前增加兩個下劃線,定義的就是私有屬性或方法 class Women: def __init__(self,name): self.name = name self.__age = 18 def __secret(self): print '%s 的年齡是 %d' %(self.name,self.__age)
lily = Women('lily') print lily.name # 私有屬性,外界不能直接訪問 #print lily.age # 私有方法,外界不能直接呼叫 lily.secret()
####面向物件中的三種形式: 封裝 繼承 多型####
1.封裝:根據職責將屬性和方法封裝到一個抽象的類中 2.繼承:實現程式碼的重用,相同的程式碼不需要重複的寫 3.多型
###########################################
封裝 1.封裝是面向物件程式設計的一大特點 2.面向物件程式設計的第一步 將屬性和方法封裝到一個抽象的類中(為什麼說是抽象的,因為類不能直接使用) 3.外界使用類建立物件,然後讓物件呼叫方法 4.物件方法的細節都被封裝在類的內部
案例1:小明愛跑步 需求 1.小明體重75.0公斤 2.每次跑步會減肥0.5公斤 3每次吃東西體重會增加1公斤 4.小美的體重是45.0公斤 class Person: def __init__(self,name,weight): # 初始化方法中增加兩個引數由外界傳遞 # self.屬性 = 形參 self.name = name self.weight = weight def __str__(self): return '我的名字叫 %s 體重是 %.2f' %(self.name,self.weight) def run(self): print '%s 愛跑步' %self.name # 在物件方法的內部,是可以直接訪問物件的屬性 self.weight -= 0.5 def eat(self): print '%s 吃東西' %self.name self.weight += 1
xx = Person('小明',75.0) xx.run() xx.eat() print xx
# 同一個類創建出來的多個物件之間,屬性互補干擾 xm = Person('小美',45.0) xm.run() xm.eat() print xm print xx
案例2:擺放傢俱 需求: 1.房子有戶型,總面積和傢俱名稱列表 新房子沒有任何的傢俱 2.傢俱有名字和佔地面積,其中 床:佔4平米 衣櫃:佔2平面 餐桌:佔1.5平米 3.將以上三件傢俱新增到房子中 4.列印房子時,要求輸出:戶型,總面積,剩餘面積,傢俱名稱列表
被使用的類應該先開發
class HouseItem: # 初始化方法 def __init__(self, name, area): self.name = name self.area = area
def __str__(self): return '[%s] 佔地 %.2f' % (self.name, self.area) """ 傢俱名稱列表 [] """ class House: def __init__(self, house_type, area): # 需要從外界傳遞進來的引數 self.house_type = house_type self.area = area # 剩餘面積(新房子沒有任何傢俱,剩餘面積=總面積) self.free_area = area # 傢俱名稱列表 self.item_list = []
def __str__(self): return '戶型:%s\n總面積:%.2f[剩餘:%.2f]\n傢俱:%s' \ % (self.house_type, self.area, self.free_area, self.item_list)
def add_item(self, item): print '要新增 %s' % item """ 1.判斷傢俱的面積是否超過房子的面積,如果超過了,提示不能新增這個傢俱 2.將 傢俱的名稱 追加到 傢俱名稱列表中去 3.用 房子的剩餘面積 - 傢俱的面積 """ if item.area > self.free_area: print '%s 的面積太大了,無法新增' %item.name # 如果不滿足,下方的程式碼就不執行 return # 將傢俱的名稱新增到列表中 self.item_list.append(item.name) # 計算剩餘面積 self.free_area -= item.area
# 1.建立傢俱 bed = HouseItem('bed', 400) print bed chest = HouseItem('chest', 2) print chest table = HouseItem('table', 1.5) print table
#2.建立房子物件 my_home = House('兩室一廳',60) # 新增傢俱到房子裡面去 my_home.add_item(bed) my_home.add_item(chest) my_home.add_item(table) print my_home
案例3:
需求: 1.士兵瑞恩有一把AK47 2.士兵可以開火(士兵開火扣動的是扳機) 3.槍 能夠 發射子彈(把子彈發射出去) 4.槍 能夠 裝填子彈 --增加子彈的數量
Soldier Gun ------------- ----------------- name model gun bullet_count #子彈數量足夠多才能完成射擊的動作 ------------- ----------------- __init__(self): __init__(self): fire(self): add_bullet(self,count):#裝填子彈的方法 shoot(self):
#練習重點:一個物件的屬性可以是另外一個類建立的物件
class Gun: def __init__(self, model): # 槍的型號 self.model = model # 子彈的數量(呼叫裝填子彈的方法來增加子彈的數量) self.bullet_count = 0
def add_bullet(self, count): self.bullet_count += count
def shoot(self): # 1.判斷子彈的數量 if self.bullet_count <= 0: print '[%s] 沒有子彈了...' % self.model return # 2.發射子彈,子彈的數量-1 self.bullet_count -= 1 # 3.提示發射資訊 print '[%s] 突突突...[%d]' %(self.model,self.bullet_count) class Soldier: def __init__(self,name): self.name = name """ 在定義屬性的時候,如果不知道設定什麼初始值,可以設定為None None表示什麼都沒有 表示一個空物件,沒有方法和屬性,是一個特殊的常量 可以將None賦值給任何一個變數 """ self.gun = None def fire(self): # 1.判斷士兵是否有槍 if self.gun == None: print '[%s] 還沒有槍' %self.name return print 'go!!! [%s]' %self.name # 士兵讓槍裝填子彈 self.gun.add_bullet(50) # 士兵讓槍發射子彈 self.gun.shoot()
# 1.建立槍物件 ak47 = Gun('AK47') # ak47.add_bullet(50) # ak47.shoot()
# 2.建立士兵物件 ryan = Soldier('Ryan') ryan.gun = ak47 ryan.fire() #print ryan.gun
###面向物件三大特徵中的繼承:### 單繼承 繼承的概念:子類擁有父類的所有屬性和方法 繼承的語法 class 類名(父類): def 子類特有的方法 Cat類是Animal類的子類,Animal類是Cat類的父類,Cat從Animal類繼承 Cat類是Animal類的派生類,Animal類是Cat類的基類,Cat類從Animal類派生
繼承的傳遞行,子類擁有父類的父類的屬性和方法 繼承的傳遞性:(爺爺 父親 兒子) 1.C類從B類繼承,B類又從A類繼承 2.那麼C類就具有B類和A類的所有屬性和方法 子類擁有父類以及父類的父類中封裝的所有屬性和方法 ## kt.eat() kt.drink() kt.run() kt.sleep()
# 子類繼承自父類,可以直接享受父類中已經封裝好的方法 # 子類中應該根據自己的職責,封裝子類特有的屬性和方法
class Animal(object): def eat(self): print '吃' def drink(self): print '喝' def run(self): print '跑' def sleep(self): print '睡'
class Cat(Animal): # 子類擁有父類的所有屬性和方法 def call(self): print '喵喵' class Hellokitty(Cat): def speak(self): print '我可以說日語'
# 建立一個貓物件 fentiao = Cat() fentiao.eat() fentiao.drink() fentiao.run() fentiao.sleep() fentiao.call()
#建立一個hellokitty物件 kt = Hellokitty() kt.speak() kt.call()
###重寫父類方法### 1.覆蓋父類的方法 2.擴充套件父類的方法 class Animal: def eat(self): print '吃' class Cat(Animal): # 子類擁有父類的所有屬性和方法 def call(self): print '喵喵'
class Hellokitty(Cat): def speak(self): print '我可以說日語' def call(self): # 針對子類特有的需求,編寫程式碼 print '歐哈有~空你起哇' # 呼叫原本在父類中封裝的程式碼 Cat.call(self) # 增加其他的子類程式碼 print '#[email protected][email protected]!#!#' kt = Hellokitty() kt.call()
下圖可以看出: 如果子類中,重寫了父類的方法,在執行中,只會呼叫在子類中重寫的父類的方法而不會呼叫父類的方法
輸出結果:
如果子類呼叫父類,則同時會輸出自己的方法和夫類的
結果如下圖:
練習:
class Bird: def __init__(self): self.hungry = True # 鳥吃過了以後就不餓了 def eat(self): if self.hungry: print 'Aaaaahhh...' self.hungry = False else: print 'No thanks'
class SongBird(Bird): def __init__(self): self.sound = 'Squawk!' Bird.__init__(self) def sing(self): print self.sound
littlebird = SongBird() littlebird.eat() littlebird.sing()
###多繼承###
class A: def test(self): print 'A-----test 方法' def demo(self): print 'A-----demo 方法' class B: def test(self): print 'B------test 方法' def demo(self): print 'B-------demo方法' class C(B,A): """多繼承可以讓子類物件,同時具有多個父類的屬性和方法""" pass
# 建立子類物件 c = C() c.test() c.demo()
注意:當多繼承時,子類括號中誰在前面就呼叫誰的方法
###新式類和舊式類### 新式類和舊式(經典)類: object是Python為所有物件提供的基類,提供有一些內建的屬性和方法,可以使用dir函式檢視 新式類:以object為基類的類,推薦使用 經典類:不以object為基類的類,不推薦使用 在python3.X中定義的類時,如果沒有指定父類,會預設使用object作為基類--python3.x中定義的類都是新式類 在python2.x中定義類時,如果沒有指定父類,則不會以object作為基類 ####推薦使用新式類#############
新式類和舊式類在多繼承時---會影響到方法的搜尋順序
為保證編寫的程式碼能夠同時在python2.x和python3.x執行 今後在定義類時,如果沒有父類,建議統一繼承自object
###繼承(私有屬性和私有方法)### 類的私有屬性和私有方法 1.子類物件不能在自己的方法內部,直接訪問父類的私有屬性和私有方法 2.子類物件可以通過父類的公有方法間接訪問到私有屬性或私有方法 私有屬性,私有方法是物件的隱私,不對外公開,外界以及子類都不能直接訪問 私有屬性,私有方法常用做一些內部的事情
class A: def __init__(self): # 在初始化方法中定義兩個屬性,一個公有屬性一個私有屬性 self.num1 = 100 self.__num2 = 200
def __test(self): print '私有方法 %d %d' % (self.num1, self.__num2)
def test(self): print '父類的共有方法 %d' % self.__num2 self.__test()
class B(A): def demo(self): # # 在子類的物件方法中,不能訪問父類的私有屬性 # print '訪問父親的私有屬性 %d' % self.__num2 # # 在子類物件的方法中,不能呼叫父類的私有方法 # self.__test() #呼叫父類的共有方法 self.test()
# 建立一個子類物件 b = B() b.demo() # b.test() # 在外界不能直接訪問物件的私有屬性/呼叫私有方法 # print b.__num2 # b.__test()
###在此可以看出,要顯示訪問物件的私有方法或屬性時,可以建立共有方法後,將私有方法新增進去,最後直接呼叫共有方法即可###
###綜合練習( 圖書管理系統)### 圖書管理系統功能: 1. 查詢 2. 增加 3. 借閱 4. 歸還 5. 退出 class Book(object): def __init__(self, name, author, state, bookIndex): self.name = name self.author = author # 0:借出 1:未借出 self.state = state self.bookIndex = bookIndex
# 列印物件時自動呼叫;str(物件) def __str__(self): return "書名:<%s> 狀態:<%s>" % (self.name, self.state) class BookManage(object): books = []
def start(self): """圖書管理初始化""" b1 = Book('python', 'Guido', 1, "INS888") self.books.append(b1) self.books.append(Book('java', 'hello', 1, "IGS888")) self.books.append(Book('c', 'westos', 1, "INS880"))
def Menu(self): self.start() while True: print(""" 圖書管理系統 1. 查詢 2. 增加 3. 借閱 4. 歸還 5. 退出
""")
choice = input("Choice:") if choice == "1": pass elif choice == '2': self.addBook() elif choice == '3': self.borrowBook() else: print("清輸入正確的選擇!")
def addBook(self): name = input("書名:") self.books.append(Book(name, input("作者:"), 1, input("書籍位置:"))) print("新增圖書%s成功!" % (name))
def borrowBook(self): name = input("借閱書籍名稱:") ret = self.checkBook(name) if ret != None: if ret.state == 0: print("書籍《%s》已經借出" % (name)) else: ret.state = 0 print("借閱%s成功" % (name)) else: print("書籍《%s》不存在!" % (name))
def checkBook(self, name): """查詢書籍是否存在""" for book in self.books: # book: Book類建立的物件 # book.name; if book.name == name: # 返回book物件 return book else: return None
bookManage = BookManage() bookManage.Menu()