【python 3】 面向对象
文章目錄
- 一、面向?qū)ο笾畬傩?/li>
- 二、面向?qū)ο笾椒?/li>
- 1)普通方法
- 2)類(lèi)方法
- 3)靜態(tài)方法
- 4)魔術(shù)方法
- 三、私有化
- 四、裝飾器
- 五、繼承
- 六、多態(tài)
- 七、單例模式
python 是面向?qū)ο蟮淖兂深A(yù)研,面向?qū)ο缶幊?#xff08;Object-oriented Programming,簡(jiǎn)稱(chēng) OOP)是一種封裝代碼的方法,面向?qū)ο蟮淖兂煽梢愿玫哪M真實(shí)世界里的事物(將其視為對(duì)象),并把描述特征的數(shù)據(jù)和代碼框(函數(shù))封裝到一起。
面向?qū)ο蟮某S酶拍?#xff1a;
- 類(lèi):可以理解成一個(gè)模板,通過(guò)它可以創(chuàng)造出無(wú)數(shù)個(gè)具體實(shí)例,可以復(fù)用且靈活性高。將類(lèi)創(chuàng)建出實(shí)例的過(guò)程又稱(chēng)為類(lèi)的實(shí)例化
- 對(duì)象:類(lèi)不能直接使用,通過(guò)類(lèi)創(chuàng)建出來(lái)的實(shí)例(對(duì)象)才能使用,表示具體的事物
- 屬性:類(lèi)中的所有變量稱(chēng)為屬性
- 方法:類(lèi)中的所有函數(shù)稱(chēng)為方法,不過(guò)和函數(shù)不同的是,類(lèi)方法至少要包含一個(gè) self 參數(shù),類(lèi)方法無(wú)法單獨(dú)使用,只能和類(lèi)實(shí)例化出來(lái)的對(duì)象一起使用。
多個(gè)對(duì)象——>提取對(duì)象的特征和動(dòng)作——>封裝到一個(gè)類(lèi)中
先有需求——>找出特征——>定義類(lèi)
類(lèi):所有對(duì)象都要有共同的特征和共同的方法
- 所有的類(lèi)要求首字母大寫(xiě),多個(gè)單詞使用駝峰式命名
- 所有的類(lèi)都從 object 中繼承過(guò)來(lái)的
一、面向?qū)ο笾畬傩?/h2>
只要遇到 class,就在內(nèi)存里邊開(kāi)辟空間,但可以不放東西。然后使用類(lèi)來(lái)構(gòu)建出一個(gè)個(gè)實(shí)際的對(duì)象。
# 定義類(lèi) class Phone():pass # 用類(lèi)來(lái)生成實(shí)際的對(duì)象,類(lèi)名加() 就找到原來(lái)的類(lèi)地址,創(chuàng)建一個(gè)和類(lèi)相同的空間,地址不同 xiaohua = Phone() print(xiaohua) xiaoming = Phone() print(xiaoming) >>> <__main__.Phone object at 0x00000197A0D6A208> <__main__.Phone object at 0x00000197A0D6A128> # 定義類(lèi) class Phone():brand = 'huawei' # 直接用類(lèi)里邊的屬性 xiaohua = Phone() print(xiaohua.brand) xiaoming = Phone() print(xiaoming.brand) >>> huawei huawei # 定義類(lèi) class Phone():brand = 'huawei' # 修改類(lèi)中的屬性 xiaohua = Phone() xiaohua.brand = 'iPhone' print(xiaohua.brand) xiaoming = Phone() print(xiaoming.brand) >>> iPhone huawei類(lèi)屬性:類(lèi)自帶的屬性
對(duì)象屬性:對(duì)象在調(diào)用了這個(gè)類(lèi)生成對(duì)象以后,動(dòng)態(tài)生成的自己的屬性。
怎么訪(fǎng)問(wèn)類(lèi)屬性:一定要用類(lèi)名來(lái)訪(fǎng)問(wèn)
Student.name = 'Jack' print(Student.name) >>> Jack二、面向?qū)ο笾椒?/h2>
方法:動(dòng)作部分
方法的分類(lèi):
- 普通方法,屬于類(lèi)里邊的方法,依賴(lài)于 self,
- 類(lèi)方法(就屬于這個(gè)類(lèi)的方法)
- 靜態(tài)方法
- 魔術(shù)方法
1)普通方法
class Phone:brand = 'xiaomi'price = 4999type = 'mate 80'# 普通方法def call(self):print('正在打電話(huà)...')# 當(dāng)構(gòu)造的對(duì)象叫 phone1 時(shí),self指向 phone1 這個(gè)對(duì)象print('self: ',self) phone1 = Phone() print('phone1:',phone1) # 輸出內(nèi)存地址 phone1.call() print('*********************************') phone2 = Phone() print('phone2:',phone2) # 輸出內(nèi)存地址 phone2.call() >>> phone1: <__main__.Phone object at 0x00000197A0D5C978> 正在打電話(huà)... self: <__main__.Phone object at 0x00000197A0D5C978>*********************************phone2: <__main__.Phone object at 0x00000197A0D63518> 正在打電話(huà)... self: <__main__.Phone object at 0x00000197A0D63518>哪個(gè)對(duì)象調(diào)用 call,就會(huì)把這個(gè)對(duì)象作為參數(shù)傳給 self 。就叫做自身。我自己調(diào)用 call,就把自己扔進(jìn)去了。
class Phone:brand = 'xiaomi'price = 4999type = 'mate 80'# 普通方法def call(self):# 當(dāng)構(gòu)造的對(duì)象叫 phone1 時(shí),self指向 phone1 這個(gè)對(duì)象print('note: ',self.note) phone1 = Phone() phone1.note = '我是 phone1 的 note' phone1.call() # 往括號(hào)里邊傳的就是 phone1 print('*********************************') phone2 = Phone() phone2.note = '我是 phone2 的 note' phone2.call() >>> note: 我是 phone1 的 note ********************************* note: 我是 phone2 的 noteself 的好處:誰(shuí)調(diào)用,self 就是誰(shuí)
這樣操作可能出現(xiàn)的問(wèn)題:不是每個(gè)對(duì)象的屬性都是相同的,或者說(shuō)有的對(duì)象沒(méi)有某些屬性。
下面這個(gè)例子,就是說(shuō)不能保證每個(gè)被傳進(jìn)來(lái)的 self 都有 address_book.
class Phone:brand = 'xiaomi'price = 4999type = 'mate 80'# 普通方法def call(self):# 當(dāng)構(gòu)造的對(duì)象叫 phone1 時(shí),self指向 phone1 這個(gè)對(duì)象 print('正在訪(fǎng)問(wèn)通訊錄...')for person in self.address_book:print(person.items())phone1 = Phone() phone1.address_book = [{'15900889976':'xiaoming'},{'13457889999':'xiaohua'}] phone1.call() # 往括號(hào)里邊傳的就是 phone1 print('\n*********************************\n') phone2 = Phone() phone2.call() >>> 正在訪(fǎng)問(wèn)通訊錄... dict_items([('15900889976', 'xiaoming')]) dict_items([('13457889999', 'xiaohua')])*********************************正在訪(fǎng)問(wèn)通訊錄... ... AttributeError: 'Phone' object has no attribute 'address_book'解決上述問(wèn)題:
魔術(shù)方法:只要用了類(lèi)的名,系統(tǒng)默認(rèn)就會(huì)執(zhí)行
先定義一個(gè)類(lèi),會(huì)創(chuàng)建一個(gè)類(lèi),用類(lèi)創(chuàng)建一個(gè)對(duì)象。
p = Phone() # 1、先找有沒(méi)有 Phone 這個(gè)空間 # 2、申請(qǐng)和 Phone 一樣的空間,地址不同 # 3、回到類(lèi)里邊看,如果類(lèi)里邊提供了魔術(shù)方法__init__ # 如果沒(méi)有,不用管,則執(zhí)行將得到的內(nèi)存空間給到 p # 如果有,則進(jìn)入 __init__,執(zhí)行里邊的動(dòng)作,此時(shí) init 里邊的 self 是當(dāng)這個(gè)對(duì)象 p 的地址,會(huì)把init里邊的屬性放到對(duì)象空間里邊。之后就不能改類(lèi)里邊的屬性了,可以改對(duì)象里邊的屬性。 # 4、執(zhí)行完 init 之后,才給對(duì)象 p 賦值init 作用:做一個(gè)標(biāo)準(zhǔn)化,保證每個(gè)通過(guò)這個(gè)類(lèi)得到的對(duì)象,都有這些屬性
class Phone:# 魔術(shù)方法之一(魔術(shù)方法:前后有 __ 的)def __init__(self): # 初始化# self 是創(chuàng)建的對(duì)象# self. ... 就表示動(dòng)態(tài)的給 self 空間中添加了兩個(gè)屬性self.brand = 'huawei'self.price = '4999'def call(self):# 當(dāng)構(gòu)造的對(duì)象叫 phone1 時(shí),self指向 phone1 這個(gè)對(duì)象 print('正在訪(fǎng)問(wèn)通訊錄...')for person in self.address_book:print(person.items()) p = Phone()在 init 中直接傳參:
class Phone:# 魔術(shù)方法之一(魔術(shù)方法:前后有 __ 的)def __init__(self, name, age): self.name = nameself.age = agedef call(self):print('{}今年{}歲了!'.format(self.name, self.age)) p = Phone('xiaoming',22) p.call() >>> xiaoming今年22歲了!創(chuàng)建對(duì)象的時(shí)候,只要傳值了,默認(rèn)就會(huì)把值送到 init 里邊。
class Cat:type = 'cat'# 通過(guò)__init__ 初始化特征def __init__(self, nickname, age, color):self.nickname = nicknameself.age = ageself.color = color# 動(dòng)作:方法def eat(self, food):print('{}喜歡吃{}'.format(self.nickname,food))def catch_mouse(self, color, weight):print('{}抓了一只{}kg的老鼠,{}色的!'.format(self.nickname, weight, color))def sleep(self,hour):if hour<5:print('繼續(xù)睡吧!')else:print('快起來(lái)抓老鼠!')def show(self):print('貓的詳情:')print(self.nickname, self.color, self.age) # 創(chuàng)建對(duì)象:利用 cat 這個(gè)類(lèi),構(gòu)建一個(gè)真實(shí)的貓 cat1 = Cat('xiaoguai', 2, 'white') # 調(diào)用這個(gè)類(lèi)的方法 cat1.catch_mouse('黑','2') cat1.eat('小金魚(yú)') cat1.sleep(5) cat1.show() >>> xiaoguai抓了一只2kg的老鼠,黑色的! xiaoguai喜歡吃小金魚(yú) 快起來(lái)抓老鼠! 貓的詳情: xiaoguai white 2普通方法的相互調(diào)用,要加 self
class Dog:def __init__(self,nickname):self.nickname = nicknamedef run(self):print('{}在院子里跑來(lái)跑去'.format(self.nickname))def eat(self):print('{}吃了很多'.format(self.nickname))self.run() d = Dog('大黃') d.eat() >>> 大黃吃了很多 大黃在院子里跑來(lái)跑去2)類(lèi)方法
普通方法的 self 就是對(duì)象,要依靠對(duì)象來(lái)調(diào)用。
類(lèi)方法直接用類(lèi)就可以調(diào)用。
類(lèi)方法,調(diào)用的時(shí)候往這里穿的不是對(duì)象,而是類(lèi)。
特點(diǎn):
- 定義需要依賴(lài)裝飾器 @classmethod
- 類(lèi)方法中的參數(shù)不是一個(gè)對(duì)象,而是當(dāng)前的類(lèi)
- 類(lèi)方法只能使用類(lèi)屬性
- 類(lèi)方法不能調(diào)用普通方法
- 類(lèi)方法,在對(duì)象還沒(méi)有創(chuàng)建的時(shí)候,就可以訪(fǎng)問(wèn),直接用類(lèi)名調(diào)用類(lèi)方法就可以了。
作用:
- 因?yàn)橹荒茉L(fǎng)問(wèn)類(lèi)屬性和類(lèi)方法,可以在對(duì)象創(chuàng)建之前,如果需要完成一些功能,就可以放到類(lèi)方法里邊來(lái)。
類(lèi)方法不能調(diào)用有self的方法,因?yàn)橛衧elf的方法的調(diào)用都要依賴(lài)于self。
類(lèi)方法的作用例子:
# 非私有屬性,可以在外邊直接訪(fǎng)問(wèn)到 class Person:age = 18def show(self):print('---------->',Person.age)print('---------->',self.age)@classmethoddef test(cls):print('---------->類(lèi)方法') Person.test() Person.age >>> ---------->類(lèi)方法 18私有類(lèi):只能在類(lèi)里邊改這個(gè)屬性,在外邊不能訪(fǎng)問(wèn)以及修改
怎么操作呢?只能依賴(lài)于類(lèi)方法對(duì)其進(jìn)行修改
class Person:__age = 18def show(self):print('---------->',Person.age)@classmethoddef test(cls):print('---------->類(lèi)方法')cls.__age = 20print('修改后的年齡是:', cls.__age)# 不創(chuàng)建對(duì)象,就想要改屬性的需求 Person.test() >>> ---------->類(lèi)方法 修改后的年齡是: 203)靜態(tài)方法
靜態(tài)方法:類(lèi)似于類(lèi)方法
- 需要裝飾器 @staticmethod
- 沒(méi)有參數(shù)
- 只能訪(fǎng)問(wèn)類(lèi)的屬性和方法,無(wú)法訪(fǎng)問(wèn)對(duì)象的屬性和方法
- 加載時(shí)機(jī)和類(lèi)方法相同
類(lèi)方法和靜態(tài)方法的不同:
- 裝飾器不同
- 參數(shù)不同,類(lèi)有參數(shù),靜態(tài)方法沒(méi)有參數(shù)
相同之處:
- 都只能訪(fǎng)問(wèn)類(lèi)的屬性和方法
- 都可以通過(guò)類(lèi)名調(diào)用訪(fǎng)問(wèn)
- 都可以在創(chuàng)建對(duì)象之前來(lái)使用,因?yàn)槎际遣灰蕾?lài)于對(duì)象的。
普通方法和上述兩者的不同:
- 普通方法沒(méi)有裝飾器
- 普通方法依賴(lài)于對(duì)象,因?yàn)槊總€(gè)普通方法都有一個(gè)self,而self表示對(duì)象本身
- 只有創(chuàng)建了對(duì)象,才可以調(diào)用普通方法
4)魔術(shù)方法
魔術(shù)方法就是一個(gè)類(lèi)/對(duì)象中的方法,和普通方法唯一的不同是,普通方法需要調(diào)用,而魔術(shù)方法是在特定時(shí)刻自動(dòng)觸發(fā)。只要你寫(xiě)了這個(gè)魔術(shù)方法,不用調(diào)也能自動(dòng)觸發(fā)。
1、_ init _:初始化魔術(shù)方法
觸發(fā)時(shí)機(jī):初始化對(duì)象時(shí)觸發(fā),不是實(shí)例化觸發(fā),但和實(shí)例化在一個(gè)操作中
2、_ new _:實(shí)例化的魔術(shù)方法
觸發(fā)時(shí)機(jī):在實(shí)例化時(shí),進(jìn)行觸發(fā)
3、_ call _:將對(duì)象當(dāng)成函數(shù)調(diào)用的魔術(shù)方法
觸發(fā)時(shí)機(jī):將對(duì)象當(dāng)做函數(shù)調(diào)用時(shí)觸發(fā)
4、_ del :delete的縮寫(xiě),析構(gòu)魔術(shù)方法
觸發(fā)時(shí)機(jī):當(dāng)對(duì)象沒(méi)引用的時(shí)候被觸發(fā),也就是沒(méi)有任何變量引用的時(shí)候。
5、_ str_ :打印對(duì)象名
觸發(fā)時(shí)機(jī):打印對(duì)象名的時(shí)候,自動(dòng)觸發(fā),調(diào)用__str_ 里邊的內(nèi)容。
一定要在這個(gè)方法中加return,return 后面的內(nèi)容就是打印對(duì)象看到的內(nèi)容
單純打印對(duì)象的名稱(chēng),對(duì)開(kāi)發(fā)者沒(méi)有太大的意義,但使用__str__ 就可以直接打印變量名。
class Person:def __init__(self, name):self.name = name p = Person('nana') print(p) >>> <__main__.Person object at 0x00000197A0D96EF0> class Person:def __init__(self, name):self.name = namedef __str__(self):return '姓名是:'+self.name p = Person('nana') print(p) >>> 姓名是:nana三、私有化
class Student:def __init__(self, name, age):self.__score = 59self.name = nameself.age = agedef __str__(self):return '姓名:{}, 年齡:{}, 分?jǐn)?shù):{}'.format(self.name, self.age, self.__score) student = Student('nana',18) print(student) >>> 姓名:nana, 年齡:18, 分?jǐn)?shù):59能改嗎?下面沒(méi)有改成功
student.age = 21 student.__score = 95 print(student) >>> 姓名:nana, 年齡:21, 分?jǐn)?shù):59面向?qū)ο笥幸环N封裝操作:
- 私有化屬性
- 定義共有的 set 和 get 方法
為什么要私有化:
- 不希望外界來(lái)改我的屬性
- 也可以修改,通過(guò) def setXXX(self,XXX)來(lái)修改,
- 還可以通過(guò)范圍限制修改。不希望外界用不合適的值進(jìn)行修改,就可以在 set 里邊判斷,是否符合我的范圍,如果在內(nèi),則可以賦值成功。
- 如果想獲取具體的某一個(gè)屬性,就可以使用 getXXX()
因?yàn)橥饨绺牟涣?#xff0c;所以如果要改的話(huà),要向外界暴露一個(gè)公有的東西,set 和 get。
- set :賦值,也就是將外界給的值給到私有的屬性
- get:取值
只要加了__name,底層就會(huì)給你改名成 _類(lèi)名__name。
四、裝飾器
在開(kāi)發(fā)中的私有化處理,裝飾器
給setAge和getAge加一層裝飾器,讓外界用起來(lái)和沒(méi)有私有化是一樣的,但功能還能和私有化一樣,加一些限制。
class Student:def __init__(self, name, age):self.__score = 59self.__name = nameself.__age = age@propertydef age(self):return self.__age@age.setterdef age(self, age):if age>0 and age<100:self.__age = ageelse: print('年齡不在規(guī)定范圍內(nèi)!')def __str__(self):return '姓名:{}, 年齡:{}, 分?jǐn)?shù):{}'.format(self.__name, self.__age, self.__score) nana = Student('nana',18) nana.age = 130 print(nana.age) print(nana) >>> 年齡不在規(guī)定范圍內(nèi)! 18 姓名:nana, 年齡:18, 分?jǐn)?shù):59五、繼承
公路(Road):屬性:公路名稱(chēng),公路長(zhǎng)度 車(chē)(Car):屬性:車(chē)名,時(shí)速方法:1、求車(chē)名在哪條公路上以多少的時(shí)速行駛了多長(zhǎng)時(shí)間2、初始化車(chē)輛屬性信息3、打印對(duì)象顯示車(chē)的屬性信息 import random class Road:def __init__(self, name, len):self.name = nameself.len = lenclass Car:def __init__(self,brand, speed):self.brand = brandself.speed = speeddef get_time(self, road):ran_time = random.randint(1,10)msg = '{}品牌的車(chē)在{}上以{}速度行駛{}個(gè)小時(shí)!'.format(self.brand,road.name,self.speed,ran_time)print(msg)def __str__(self):return '{}品牌的車(chē),速度:{}'.format(self.brand,self.speed) #創(chuàng)建實(shí)例化對(duì)象 r = Road('京藏高速',12000) print(r.name) audi = Car('Audi',120) print(audi) audi.get_time(r) >>> 京藏高速 Audi品牌的車(chē),速度:120 Audi品牌的車(chē)在京藏高速上以120速度行駛2個(gè)小時(shí)!1)has a 關(guān)系:
has a:一個(gè)類(lèi)里邊有另一個(gè)類(lèi),不完全是繼承關(guān)系,但是是一種包含關(guān)系。
# 創(chuàng)建三個(gè)類(lèi),則系統(tǒng)開(kāi)辟三個(gè)空間,分別存這三個(gè)類(lèi)的信息 # 然后調(diào)用的時(shí)候,就是創(chuàng)建三個(gè)對(duì)象 # student對(duì)象,需要name,computer # 這里的computer也是一種類(lèi)型,不過(guò)是自定義類(lèi)型 # list、int 等都是系統(tǒng)提供的類(lèi)型 # class Computer:pass class Book:pass class Student:pass class Computer:def __init__(self, brand, type, color):self.brand = brandself.type = typeself.color = colordef online(self):print('正在使用電腦上網(wǎng)...')def __str__(self):return self.brand + '---' + self.type + '---' + self.colorclass Book:def __init__(self, bname, author, number):self.bname = bnameself.author = authorself.number = numberdef __str__(self):return self.name + '---' + self.author + '---' + str(self.number)class Student: # has a def __init__(self,name,computer,book):self.name = nameself.computer = computerself.books=[]self.books.append(book)def borrow_book(self, book):for book1 in self.books:if book1.bname == book.bname:print('已經(jīng)借過(guò)了')breakelse:# 將這本書(shū)加到列表中self.books.append(book)print('添加成功!')def show_book(self):for book in self.books:print(book.bname)def __str__(self):return self.name + '---' + str(self.computer) + '---' + str(self.books)# 創(chuàng)建對(duì)象 computer = Computer('mac','mac pro 2018','深灰色') book = Book('盜墓筆記','南派三叔',10) student = Student('nana',computer,book) print(student) book1 = Book('鬼吹燈','天下霸唱',8) student.show_book() student.borrow_book(book1) print('--------------') student.show_book() >>> nana---mac---mac pro 2018---深灰色---[<__main__.Book object at 0x000001F0F2343668>] 盜墓筆記 添加成功! -------------- 盜墓筆記 鬼吹燈知識(shí)點(diǎn):
- 理解 has a,一個(gè)類(lèi)里邊使用了另外一種自定義類(lèi)型
- student 里邊使用了 computer 和 book
- 類(lèi)型:
- 系統(tǒng)類(lèi)型:str int float list dict tuple set 等
- 自定義類(lèi)型:自定義的類(lèi),都可以看做一種類(lèi)型
s = Student() s是Student類(lèi)的對(duì)象
2)is a 的關(guān)系:
如果 A 是 B,那么 B 就是 A 的基類(lèi),基類(lèi)就是父類(lèi)。
為什么要層層繼承:
很多類(lèi)中的方法是重復(fù)的,所以把每個(gè)類(lèi)中間都具備的共同特征或共同屬性,放到一個(gè)大類(lèi)里邊,其他的類(lèi)直接繼承來(lái)用就好啦。
# 基類(lèi):父類(lèi) base class class Student:def __init__(self, name, age):self.name = nameself.age = agedef eat(self):print(self.name + '正在吃飯!')def run(self):print(self.name + '正在跑步!') class Employee:def __init__(self, name, age):self.name = nameself.age = age class Doctor:pass使用繼承的方法:把父類(lèi)里邊的東西都繼承過(guò)來(lái)了,調(diào)用的時(shí)候是跑到父類(lèi)里邊去調(diào)用的。
所有的類(lèi)默認(rèn)繼承的就是 Object,是所有類(lèi)的父類(lèi)。
什么時(shí)候需要繼承:
- 多個(gè)類(lèi)屬于相同的大類(lèi)
- 多個(gè)類(lèi)有相同的代碼,冗余,代碼可讀性不高
如何繼承:
- 將相同的代碼提取出來(lái),得到一個(gè)基類(lèi)
- 讓子類(lèi)繼承基類(lèi) class Student(Person): ...
特點(diǎn):
- 如果類(lèi)中不定義 init,去父類(lèi)找
- 如果需要定義自己的 init,需要在子類(lèi)的 init 中調(diào)用父類(lèi)的
- 如何調(diào)用父類(lèi)的 init:
- super().init(參數(shù))
- super(類(lèi)名,self).init(參數(shù))
- 如果父類(lèi)的方法無(wú)法滿(mǎn)足子類(lèi)的需求,子類(lèi)中會(huì)重寫(xiě)一個(gè)同名方法,這個(gè)方法會(huì)把父類(lèi)的方法覆蓋。也就是如果父類(lèi)有 eat,子類(lèi)也有eat,默認(rèn)先找自己的,再找父類(lèi),會(huì)把父類(lèi)的覆蓋。
子類(lèi)定義 init:都要把父類(lèi)的 init 調(diào)用一下才可以
所有的類(lèi)傳參數(shù)都是傳到 init 去了,所以,super 傳參也就傳到 init去了。
super其實(shí)是一個(gè)類(lèi),既然是個(gè)類(lèi),那么就要傳參數(shù),往init傳參數(shù)。
調(diào)用的目的:保證把共同的特征拿過(guò)來(lái)。
# super() 表示父類(lèi)對(duì)象 super().__init__()無(wú)參數(shù)情況下定義 init:
class Person:def __init__(self):self.name = 'nana'self.age = 14def eat(self):print(self.name + '正在吃飯!')def run(self):print(self.name + '正在跑步!') class Students(Person):def __init__(self):print('-----> student 的 init')super().__init__() s = Students() # 執(zhí)行步驟,先調(diào) __new__,產(chǎn)生新空間傳給 __init__,student什么都沒(méi)有,就會(huì)到其父類(lèi)里邊找 s.run() >>> -----> student 的 init nana正在跑步!有參數(shù)情況下定義 init:
為什么要在每個(gè)子類(lèi)定義 init:因?yàn)槊總€(gè)子類(lèi)都會(huì)有他的特有屬性和方法。
class Person:def __init__(self, name, age):self.name = nameself.age = agedef eat(self):print(self.name + '正在吃飯!')def run(self):print(self.name + '正在跑步!') class Students(Person):def __init__(self, name, age):print('-----> student 的init')super().__init__(name, age) class Employee(Person):pass class Dctor(Person):passs = Students('Jack',18) # 執(zhí)行步驟,先調(diào) __new__,產(chǎn)生新空間傳給 __init__,student什么都沒(méi)有,就會(huì)到其父類(lèi)里邊找 s.run() e = Employee('lily',13) e.run() >>> -----> student 的init Jack正在跑步! lily正在跑步!并非所有類(lèi)的屬性都是共有的,類(lèi)都會(huì)有自己特有的東西,所以,需要定義個(gè)體的不同之處:
class Person:def __init__(self, name, age):self.name = nameself.age = agedef eat(self):print(self.name + '正在吃飯!')def run(self):print(self.name + '正在跑步!')class Students(Person):def __init__(self, name, age, classes):super().__init__(name, age) # 利用 super 把父類(lèi)有的屬性拿過(guò)來(lái)self.classes = classes # 自己定義的屬性def study(self, course):print('{}正在學(xué){}'.format(self.name, course))def eat(self, food): # super().eat()print('{}正在吃飯,喜歡吃{}'.format(self.name, food))class Employee(Person):def __init__(self, name, age, salary, manager):super().__init__(name, age)self.salary = salaryself.manager = managerclass Doctor(Person):def __init__(self, name, age, patients):super().__init__(name, age) # super(Doctor, self).__init__(name, age) # 和上面等價(jià),不過(guò)底層會(huì)做一個(gè) isinstance 的判斷,判斷傳進(jìn)來(lái)的是不是 Doctorself.patients = patientss = Students('Jack',18, '1611') # 執(zhí)行步驟,先調(diào) __new__,產(chǎn)生新空間傳給 __init__,student什么都沒(méi)有,就會(huì)到其父類(lèi)里邊找 s.run() s.study('python基礎(chǔ)') s.eat('紅燒肉') e = Employee('lily',23, 10000, 'king') e.run() list1 = ['tom','jack','json','lili'] d = Doctor('lucy', 30, list1) d.run() >>> Jack正在跑步! Jack正在學(xué)python基礎(chǔ) Jack正在吃飯,喜歡吃紅燒肉 lily正在跑步! lucy正在跑步!練習(xí):工資管理程序
編寫(xiě)一個(gè)工資管理程序,管理以下四類(lèi)人: worker, salesman, manager, salemanager。 所有員工都具有工號(hào),姓名,工資等屬性,有設(shè)置姓名,獲取姓名,獲取員工號(hào),計(jì)算工資等方法。 1)worker:具有工作小時(shí)數(shù)和時(shí)薪的屬性,工資 = 小時(shí)*時(shí)薪 2)salesman:具有銷(xiāo)售額和提成比例的屬性,工資 = 銷(xiāo)售額*提成 3)manager:固定月薪 4)salasmanager:工資 = 銷(xiāo)售額*提成比例*月薪 請(qǐng)完成以下功能: 1)添加所有類(lèi)型的人員 2)計(jì)算月薪 3)顯示所有人工資 class Person:def __init__(self, no, name, salary):self.no = noself.name = nameself.salary = salarydef __str__(self):msg = '工號(hào):{}, 姓名:{}, 本月工資:{}'.format(self.no, self.name, self.salary)return msgdef getSalary(self):return self.salary class Worker(Person):def __init__(self, no, name, salary, hours, per_hour_money):super().__init__(no, name, salary)self.hours = hoursself.per_hour_money = per_hour_moneydef getSalary(self):money = self.hours*self.per_hour_moneyself.salary += moneyreturn self.salary class Salesman(Person):def __init__(self, no, name, salary, salemoney, percent):super().__init__(no, name, salary)self.salemoney = salemoneyself.percent = percentdef getSalary(self):money = self.salemoney*self.percentself.salary += moneyreturn self.salary # 創(chuàng)建對(duì)象 worker = Worker('001','king',2000,160,50) S = worker.getSalary() print('月薪是:',S) print(worker) saler = Salesman('002','lucy',5000,5000000,0.003) s = saler.getSalary() print('月薪是:',s) print(saler) >>> 月薪是: 10000 工號(hào):001, 姓名:king, 本月工資:10000 月薪是: 20000.0 工號(hào):002, 姓名:lucy, 本月工資:20000.0有重名的方法,后面的會(huì)把前面的覆蓋掉:
class Person:def __init__(self, name):self.name = namedef eat(self):print('--------eat1')def eat(self,food):print('--------eat',food) p = Person() p.eat() >>> TypeError: eat() missing 1 required positional argument: 'food'p = Person('jack') p.eat('紅燒肉') >>> --------eat 紅燒肉python 允許多繼承:
class A:def test(self):print('AAAAAAAAA') class B:def test1(self):print('BBBBBBBBB') class C(A,B):def test2(self):print('CCCCCCCCC') c = C() c.test1() c.test() >>> BBBBBBBBB AAAAAAAAA多繼承的搜索順序:
class Base:def test(self):print('-------Base---------') class A(Base):def test(self):print('AAAAAAAAAAAAAAAAAAAA') class B(Base):def test(self):print('BBBBBBBBBBBBBBBBBBBB') class C(Base):def test(self):print('CCCCCCCCCCCCCCCCCCCC') class D(A, B, C):pass d = D() d.test() import inspect print(inspect.getmro(D)) print(D.__mro__) # 獲取搜索順序方法二 >>> AAAAAAAAAAAAAAAAAAAA (<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Base'>, <class 'object'>)python 允許多繼承:
def 子類(lèi)(父類(lèi)1,父類(lèi)2):pass父類(lèi)中有相同的方法時(shí),搜索順序:從左至右,深度優(yōu)先
六、多態(tài)
python 類(lèi)似于多態(tài),但是是依賴(lài)于 isinstance 來(lái)判斷的。
isinstance(obj, 類(lèi)): 判斷obj是不是該類(lèi)的對(duì)象或該類(lèi)子類(lèi)的對(duì)象 class Person:def __init__(self,name):self.name = namedef feed_pet(self, pet):if isinstance(pet, Pet): print('{}喜歡養(yǎng)寵物:{},昵稱(chēng)是:{}'.format(self.name,pet.role, pet.nickname))else:print('不是寵物,不能養(yǎng)!')class Pet:role = 'Pet'def __init__(self, nickname, age):self.nickname = nicknameself.age = agedef show(self):print('昵稱(chēng):{},年齡:{}'.format(self.nickname, self.age)) class Cat(Pet):role = 'Cat'def catch_mouse(self):print('抓老鼠...') class Dog(Pet):role = 'Dog'def whatch_house(self):print('看家高手...') class Tiger:def eat(self):print('太可怕了...') # 創(chuàng)建對(duì)象 cat = Cat('huahua', 2) dog = Dog('dahuang', 4) tiger = Tiger() person = Person('nana') person.feed_pet(cat) person.feed_pet(tiger) >>> nana喜歡養(yǎng)寵物:Cat,昵稱(chēng)是:huahua 不是寵物,不能養(yǎng)!七、單例模式
開(kāi)發(fā)模式:單例模式
單個(gè)對(duì)象就叫單例模式
class Student:pass s = Student() s1 = Student() s2 = Student()上面這種創(chuàng)建對(duì)象的模式,會(huì)導(dǎo)致每次調(diào)用這個(gè)類(lèi),系統(tǒng)都會(huì)給這個(gè)對(duì)象分配一個(gè)空間,多個(gè)地址。
單例模式,開(kāi)發(fā)過(guò)程中,一個(gè)實(shí)例就搞定的,不需要每次實(shí)例化的時(shí)候都開(kāi)辟一個(gè)空間。也就是每次調(diào)用這個(gè)類(lèi)的時(shí)候,都指向同一個(gè)地址,不會(huì)占用很多空間。
調(diào)用的時(shí)候底層的操作:
- 先找 new,幫我們產(chǎn)生內(nèi)存地址,產(chǎn)生后賦值給 __instance,返回給 init
- 再找 init,如果找不到,就找父類(lèi)的init
- 最后賦值地址給對(duì)象
總結(jié)
以上是生活随笔為你收集整理的【python 3】 面向对象的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【python 2】python 进阶
- 下一篇: Linux和类Unix系统上5个惊艳的开