一、多態(tài)
1.概念
一種事物的多種體現(xiàn)形式,函數(shù)的重寫其實就是多態(tài)的一種體現(xiàn)
在Python中,多態(tài)指的是父類的引用指向子類的對象
代碼演示:
#父類 class Animal(object): pass #子類 class Dog(Animal): pass class Cat(Animal): pass #定義變量 a = [] #a是list類型 b = Animal() #b是Animal類型 c = Cat() #c是Cat類型 #isinstance():判斷一個對象是否屬于某種類型【系統(tǒng)還是自定義的類型】 print(isinstance(a,list)) print(isinstance(b,Animal)) print(isinstance(c,Cat)) print(isinstance(c,Animal)) #True print(isinstance(b,Dog)) #False #結(jié)論:子類對象可以是父類類型,但是,父類的對象不能是子類類型
2.使用
案例:人可以喂貓,喂狗
思路:
a.定義動物類【父類】
b.定義子類,繼承自動物類
c.定義人類
d.使用多態(tài),優(yōu)化
代碼演示:
duoTaiDemo.py文件
from duotai.person import Person from duotai.cat import Cat from duotai.dog import Dog #1.創(chuàng)建一個Person的對象 p = Person() #2.創(chuàng)建一個Cat的對象 c = Cat("小白") #3.人執(zhí)行自己的行為 p.feedAnimal(c) d = Dog("旺財") p.feedAnimal(d)person.py文件
class Person(object): """ def feedCat(self,cat): print("喂貓:",cat.name) cat.eat() def feedDog(self,dog): print("喂貓:",dog.name) dog.eat() """ #多態(tài) #ani被當(dāng)做父類的引用 ,當(dāng)傳參的時候,實參是一個子類對象的時候,則體現(xiàn)出了 多態(tài)的應(yīng)用 def feedAnimal(self,ani): #ani = c c = Cat("") print("喂動物:", ani.name) ani.eat()animal.py文件
class Animal(object): def __init__(self,name): self.name = name def eat(self): print("eating")cat.py文件
from duotai.animal import Animal class Cat(Animal): def __init__(self,name): super(Cat,self).__init__(name)dog.py文件
from duotai.animal import Animal class Dog(Animal): def __init__(self,name): super(Dog,self).__init__(name)總結(jié):
? 簡化代碼,提高代碼的可讀性,可維護性
二、獲取對象信息
type() isintance() dir()
代碼演示:
#1.type() :判斷一個對象所屬的類型 num = 10 print(type(num)) print(type("hello")) class Check(object): pass c = Check() print(type(c)) #使用==判斷type返回的結(jié)果 print(type(12) == type(57)) #True print(type(12) == type("57")) #False #使用type返回的結(jié)果和數(shù)據(jù)類型直接判斷 print(type(12) == int) #2.isintance() :判斷一個對象是否屬于某種指定的數(shù)據(jù)類型 #自定義的類中 class Dog(object): pass d = Dog() print(isinstance(d,Dog)) print(isinstance([1,2,4],list)) #特殊用法:可以判斷一個對象是否屬于多種數(shù)據(jù)類型中的某一種 print(isinstance([1,2,4],(tuple,list))) #3.dir() :列出指定對象中所包含的所有的內(nèi)容【成員變量,成員方法】 dict = {} print(dir(dict)) print(dir("abc")) print(dir(d))
三、類中特殊的屬性和方法
1.實例屬性和類屬性
1.1實例屬性和類屬性的區(qū)別【面試題】
a.定義的位置不同,類屬性時直接定義在類中,實例屬性定義在構(gòu)造函數(shù)中
b.訪問的方式不同,類屬性使用類名直接訪問,實例屬性使用對象訪問
c.在內(nèi)存中出現(xiàn)的時機不同,類屬性隨著類的出現(xiàn)而出現(xiàn),實例屬性隨著對象的出現(xiàn)而出現(xiàn)
d.優(yōu)先級不同,實例屬性的優(yōu)先級高于類屬性
代碼演示:
class Person(object): #1.定義位置 #類屬性:直接定義在類中 name = "abc" age = 0 def __init__(self,name): #實例屬性:定義在構(gòu)造函數(shù)中 self.name = name #2.訪問方式 print(Person.name) #類屬性:類名.屬性 或者 對象.屬性 p = Person("hello") print(p.name) #實例屬性:對象.屬性 #3.優(yōu)先級不同:實例屬性的優(yōu)先級高于類屬性 print(p.name) #hello #4.不同對象的類屬性在內(nèi)存中是不是同一塊空間?----->不是 p1 = Person("小白") p2 = Person("小紅") print(p1.age) print(p2.age) p1.age = 33 print(p1.age) print(p2.age) print(id(p1.age)) print(id(p2.age)) """ 0 0 33 0 1420404832 1420403776 """ #注意:盡量避免類屬性和實例屬性的重名 #刪除屬性【類屬性,實例屬性】 del p1.age
1.2動態(tài)添加屬性和方法
代碼演示:
from types import MethodType class Person(object): #__slots__ = ("name","age") pass #1.動態(tài)添加屬性 per = Person() str = "fjsgh" per.name = str #2.動態(tài)添加方法 def say(self): print("fhsj") """ per.test = say per.test(per) """ #弊端:違背了普通函數(shù)定義 #解決方案:MethodType類,存在于types模塊下 #類似于偏函數(shù) #參數(shù):函數(shù)名,對象 #作用:在現(xiàn)有函數(shù)的基礎(chǔ)上生成了一個對象【新的函數(shù)】,賦值給成員變量,則認(rèn)為給對象添加了一個成員方法 per.test = MethodType(say,per) per.test()
2.類方法和靜態(tài)方法
類方法:使用@classmethod裝飾器修飾的方法,被稱為類方法,可以通過類名調(diào)用,也可以通過對象調(diào)用,但是一般情況下使用類名調(diào)用
靜態(tài)方法:使用@staticmethod裝飾器修飾的方法,被稱為靜態(tài)方法,可以通過類名調(diào)用,也可以通過對象調(diào)用,但是一般情況下使用類名調(diào)用
代碼演示:
class Test(object): #1.類屬性 age = 100 def __init__(self,name): #2.實例屬性 self.name = name #3.成員方法,通過對象調(diào)用 #必須有一個參數(shù),這個參數(shù)一般情況下為self,self代表是當(dāng)前對象 def func(self): print("func") #4.類方法 """ a.必須有一個參數(shù),這個參數(shù)一般情況下為cls,cls代表的是當(dāng)前類 b.類方法是屬于整個類的,并不是屬于某個具體的對象,在類方法中禁止出現(xiàn)self c.在類方法的內(nèi)部,可以直接通過cls調(diào)用當(dāng)前類中的屬性和方法 d.在類方法的內(nèi)部,可以通過cls創(chuàng)建對象 """ @classmethod def test(cls): print("類方法") print(cls) #<class 'methodDemo01.Test'> print(cls.age) #6 #注意:cls完全當(dāng)做當(dāng)前類使用 c = cls("hello") c.func() #7.靜態(tài)方法 @staticmethod def show(): print("靜態(tài)方法") t = Test("hjfsh") t.func() #5,.調(diào)用類方法 Test.test() #類名.類方法的名稱() t.test() #對象.類方法的名稱() #7。調(diào)用靜態(tài)方法 Test.show() t.show()總結(jié):實例方法【成員方法】、類方法以及靜態(tài)方法之間的區(qū)別
a.語法上
? 實例方法:第一個參數(shù)一般為self,在調(diào)用的時候不需要傳參,代表的是當(dāng)前對象【實例】
? 靜態(tài)方法:沒有特殊要求
? 類方法:第一個參數(shù)必須為cls,代表的是當(dāng)前類
b.在調(diào)用上
? 實例方法:只能對象
? 靜態(tài)方法:對象 或者 類
? 類方法:對象 或者 類
c.在繼承上【相同點】
? 實例方法、靜態(tài)方法、類方法:當(dāng)子類中出現(xiàn)和父類中重名的函數(shù)的時候,子類對象調(diào)用的是子類中的方法【重寫】
代碼演示:
class SuperClass(object): @staticmethod def show(): print("父類中的靜態(tài)方法") @classmethod def check(cls): print("父類中的類方法") class SubClass(SuperClass): pass s = SubClass() s.show() s.check()注意:注意區(qū)分三種函數(shù)的書寫形式,在使用,沒有絕對的區(qū)分
3.類常用屬性
__name__ 通過類名訪問,獲取類名字符串 不能通過對象訪問,否則報錯 __dict__ 通過類名訪問,獲取指定類的信息【類方法,靜態(tài)方法,成員方法】,返回的是一個字典 通過對象訪問,獲取的該對象的信息【所有的屬性和值】,,返回的是一個字典 __bases__ 通過類名訪問,查看指定類的所有的父類【基類】
代碼演示:
class Animal(object): def __init__(self,arg): super(Animal, self).__init__() self.arg = arg class Tiger(Animal): age = 100 height = 200 def __init__(self,name): #super(Tiger, self).__init__(name) self.name = name def haha(self): print("haha") @classmethod def test(cls): print("cls") @staticmethod def show(): print("show") if __name__ == "__main__": #1.__name__ print(Tiger.__name__) #Tiger t = Tiger("") #print(t.__name__) #AttributeError: 'Tiger' object has no attribute '__name__' #2.__dict__ print(Tiger.__dict__) #類屬性,所有的方法 print(t.__dict__) #實例屬性 #3.__bases__,獲取指定類的所有的父類,返回的是一個元組 print(Tiger.__bases__)
四、運算符重載【了解】
運算符重載其實就是函數(shù)重寫
代碼演示:
print(1 + 1) print("1" + "1") #print("1" + 1) #不同的數(shù)據(jù)類型進行加法運算得到的是不同的解釋 #思考問題:兩個對象相加? class Person(object): def __init__(self,num): self.num = num def __str__(self): return "num=" + str(self.num) def __add__(self, other): #兩個對象相加得到的結(jié)果仍然為一個對象 return Person(self.num + other.num) #Peson(30) p1 = Person(10) p2 = Person(20) print(p1) #10 print(p2) #20 print(p1 + p2) #30 #p1 + p2----->p1.__add__(p2),
五、單例設(shè)計模式【擴展】
1.概念
什么是設(shè)計模式
? 經(jīng)過已經(jīng)總結(jié)好的解決問題的方案
? 23種設(shè)計模式,比較常用的是單例設(shè)計模式,工廠設(shè)計模式,代理模式,裝飾模式
什么是單例設(shè)計模式
? 單個實例【對象】
? 在程序運行的過程中,確保某一個類只能有一個實例【對象】,不管在哪個模塊中獲取對象,獲取到的都是同一個對象
? 單例設(shè)計模式的核心:一個類有且僅有一個實例,并且這個實例需要應(yīng)用在整個工程中
2.應(yīng)用場景
實際應(yīng)用:數(shù)據(jù)庫連接池操作-----》應(yīng)用程序中多處需要連接到數(shù)據(jù)庫------》只需要創(chuàng)建一個連接池即可,避免資源的浪費
3.實現(xiàn)
3.1模塊
Python的模塊就是天然的單例設(shè)計模式
模塊的工作原理:
? import xxx,模塊被第一次導(dǎo)入的時候,會生成一個.pyc文件,當(dāng)?shù)诙螌?dǎo)入的時候,會直接加載.pyc文件,將不會再去執(zhí)行模塊源代碼
3.2使用new【掌握】
__new__():實例從無到有的過程【對象的創(chuàng)建過程】代碼演示:
class Singleton(object): #類屬性 instance = None #類方法 @classmethod def __new__(cls, *args, **kwargs): #如果instance的值不為None,說明已經(jīng)被實例化了,則直接返回;如果為NOne,則需要被實例化 if not cls.instance: cls.instance = super(Singleton,cls).__new__(*args, **kwargs) return cls.instance class MyClass(Singleton): pass #當(dāng)創(chuàng)建對象的時候自動被調(diào)用 one = MyClass() two = MyClass() print(id(one)) print(id(two)) print(one is two)
3.3裝飾器【掌握】
代碼演示:
#單例類:將裝飾器作用于一個類上 def singleton(cls): #類屬性 instance = {} #成員方法 def getSingleton(*args, **kwargs): #思路:如果cls在字典中,則直接返回;如果不存在,則cls作為key,對象作為value,添加到字典中 if cls not in instance: instance[cls] = cls(*args, **kwargs) return instance[cls] return getSingleton @singleton class Test(object): pass t1 = Test() t2 = Test() print(id(t1) == id(t2)) print(t1 is t2)
3.4使用在類中【掌握】
代碼演示:
#單例類 class Foo(object): #1.聲明一個變量【類屬性】 instance = None #2.向外界提供一個公開的方法,用于返回當(dāng)前類唯一的對象 #方法命名格式:defaultInstance,currentInstance ,getInstance @classmethod def getInstance(cls): if cls.instance: return cls.instance else: #實例化 cls.instance = cls() return cls.instance obj1 = Foo.getInstance() obj2 = Foo.getInstance() print(id(obj1) == id(obj2)) print(obj1 is obj2)