Python多態(tài)

一逐沙、多態(tài)

1.概念

一種事物的多種體現(xiàn)形式偏序,函數(shù)的重寫(xiě)其實(shí)就是多態(tài)的一種體現(xiàn)

在Python中哼御,多態(tài)指的是父類的引用指向子類的對(duì)象

代碼演示:

#父類
class Animal(object):
    pass

#子類
class Dog(Animal):
    pass

class Cat(Animal):
    pass

#定義變量
a = []   #a是list類型
b = Animal()  #b是Animal類型
c = Cat()  #c是Cat類型

#isinstance():判斷一個(gè)對(duì)象是否屬于某種類型【系統(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é)論:子類對(duì)象可以是父類類型,但是兰粉,父類的對(duì)象不能是子類類型

2.使用

案例:人可以喂貓故痊,喂狗

思路:

a.定義動(dòng)物類【父類】

b.定義子類,繼承自動(dòng)物類

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)建一個(gè)Person的對(duì)象
p = Person()

#2.創(chuàng)建一個(gè)Cat的對(duì)象
c = Cat("小白")

#3.人執(zhí)行自己的行為
p.feedAnimal(c)

d = Dog("旺財(cái)")
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)傳參的時(shí)候,實(shí)參是一個(gè)子類對(duì)象的時(shí)候焰络,則體現(xiàn)出了 多態(tài)的應(yīng)用
    def feedAnimal(self,ani):   #ani = c   c = Cat("")
        print("喂動(dòng)物:", 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é):

? 簡(jiǎn)化代碼戴甩,提高代碼的可讀性,可維護(hù)性

二舔琅、獲取對(duì)象信息

type() isintance() dir()

代碼演示:

#1.type() :判斷一個(gè)對(duì)象所屬的類型
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()  :判斷一個(gè)對(duì)象是否屬于某種指定的數(shù)據(jù)類型
#自定義的類中
class Dog(object):
    pass

d = Dog()
print(isinstance(d,Dog))
print(isinstance([1,2,4],list))

#特殊用法:可以判斷一個(gè)對(duì)象是否屬于多種數(shù)據(jù)類型中的某一種
print(isinstance([1,2,4],(tuple,list)))

#3.dir()  :列出指定對(duì)象中所包含的所有的內(nèi)容【成員變量等恐,成員方法】
dict = {}
print(dir(dict))

print(dir("abc"))

print(dir(d))

三洲劣、類中特殊的屬性和方法

1.實(shí)例屬性和類屬性

1.1實(shí)例屬性和類屬性的區(qū)別【面試題】

a.定義的位置不同备蚓,類屬性時(shí)直接定義在類中课蔬,實(shí)例屬性定義在構(gòu)造函數(shù)中

b.訪問(wèn)的方式不同,類屬性使用類名直接訪問(wèn)郊尝,實(shí)例屬性使用對(duì)象訪問(wèn)

c.在內(nèi)存中出現(xiàn)的時(shí)機(jī)不同二跋,類屬性隨著類的出現(xiàn)而出現(xiàn),實(shí)例屬性隨著對(duì)象的出現(xiàn)而出現(xiàn)

d.優(yōu)先級(jí)不同流昏,實(shí)例屬性的優(yōu)先級(jí)高于類屬性

代碼演示:

class Person(object):
    #1.定義位置
    #類屬性:直接定義在類中
    name = "abc"
    age = 0

    def __init__(self,name):
        #實(shí)例屬性:定義在構(gòu)造函數(shù)中
        self.name = name


#2.訪問(wèn)方式
print(Person.name)  #類屬性:類名.屬性 或者 對(duì)象.屬性

p = Person("hello")
print(p.name)   #實(shí)例屬性:對(duì)象.屬性

#3.優(yōu)先級(jí)不同:實(shí)例屬性的優(yōu)先級(jí)高于類屬性
print(p.name)   #hello

#4.不同對(duì)象的類屬性在內(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
"""

#注意:盡量避免類屬性和實(shí)例屬性的重名

#刪除屬性【類屬性,實(shí)例屬性】
del p1.age
1.2動(dòng)態(tài)添加屬性和方法

代碼演示:

from  types import MethodType


class Person(object):
    #__slots__ = ("name","age")
    pass


#1.動(dòng)態(tài)添加屬性
per = Person()
str = "fjsgh"
per.name = str

#2.動(dòng)態(tài)添加方法
def say(self):
    print("fhsj")
"""
per.test = say
per.test(per)
"""

#弊端:違背了普通函數(shù)定義
#解決方案:MethodType類况凉,存在于types模塊下

#類似于偏函數(shù)
#參數(shù):函數(shù)名谚鄙,對(duì)象
#作用:在現(xiàn)有函數(shù)的基礎(chǔ)上生成了一個(gè)對(duì)象【新的函數(shù)】,賦值給成員變量刁绒,則認(rèn)為給對(duì)象添加了一個(gè)成員方法
per.test = MethodType(say,per)
per.test()

2.類方法和靜態(tài)方法

類方法:使用@classmethod裝飾器修飾的方法闷营,被稱為類方法,可以通過(guò)類名調(diào)用知市,也可以通過(guò)對(duì)象調(diào)用傻盟,但是一般情況下使用類名調(diào)用

靜態(tài)方法:使用@staticmethod裝飾器修飾的方法,被稱為靜態(tài)方法嫂丙,可以通過(guò)類名調(diào)用娘赴,也可以通過(guò)對(duì)象調(diào)用,但是一般情況下使用類名調(diào)用

代碼演示:

class Test(object):
    #1.類屬性
    age = 100

    def __init__(self,name):
        #2.實(shí)例屬性
        self.name = name

    #3.成員方法,通過(guò)對(duì)象調(diào)用
    #必須有一個(gè)參數(shù)跟啤,這個(gè)參數(shù)一般情況下為self诽表,self代表是當(dāng)前對(duì)象
    def func(self):
        print("func")

    #4.類方法
    """
    a.必須有一個(gè)參數(shù),這個(gè)參數(shù)一般情況下為cls隅肥,cls代表的是當(dāng)前類
    b.類方法是屬于整個(gè)類的关顷,并不是屬于某個(gè)具體的對(duì)象,在類方法中禁止出現(xiàn)self
    c.在類方法的內(nèi)部武福,可以直接通過(guò)cls調(diào)用當(dāng)前類中的屬性和方法
    d.在類方法的內(nèi)部议双,可以通過(guò)cls創(chuàng)建對(duì)象
    """
    @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()       #對(duì)象.類方法的名稱()

#7。調(diào)用靜態(tài)方法
Test.show()
t.show()

總結(jié):實(shí)例方法【成員方法】捉片、類方法以及靜態(tài)方法之間的區(qū)別

a.語(yǔ)法上

? 實(shí)例方法:第一個(gè)參數(shù)一般為self平痰,在調(diào)用的時(shí)候不需要傳參,代表的是當(dāng)前對(duì)象【實(shí)例】

? 靜態(tài)方法:沒(méi)有特殊要求

? 類方法:第一個(gè)參數(shù)必須為cls伍纫,代表的是當(dāng)前類

b.在調(diào)用上

? 實(shí)例方法:只能對(duì)象

? 靜態(tài)方法:對(duì)象 或者 類

? 類方法:對(duì)象 或者 類

c.在繼承上【相同點(diǎn)】

? 實(shí)例方法宗雇、靜態(tài)方法、類方法:當(dāng)子類中出現(xiàn)和父類中重名的函數(shù)的時(shí)候莹规,子類對(duì)象調(diào)用的是子類中的方法【重寫(xiě)】

代碼演示:

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ù)的書(shū)寫(xiě)形式赔蒲,在使用,沒(méi)有絕對(duì)的區(qū)分

3.類常用屬性

__name__
  通過(guò)類名訪問(wèn),獲取類名字符串
  不能通過(guò)對(duì)象訪問(wèn)舞虱,否則報(bào)錯(cuò)
  
__dict__
  通過(guò)類名訪問(wèn)欢际,獲取指定類的信息【類方法,靜態(tài)方法矾兜,成員方法】损趋,返回的是一個(gè)字典
  通過(guò)對(duì)象訪問(wèn),獲取的該對(duì)象的信息【所有的屬性和值】椅寺,浑槽,返回的是一個(gè)字典
  
__bases__
  通過(guò)類名訪問(wèn),查看指定類的所有的父類【基類】

代碼演示:

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__)   #實(shí)例屬性

    #3.__bases__桐玻,獲取指定類的所有的父類,返回的是一個(gè)元組
    print(Tiger.__bases__)

四荆萤、運(yùn)算符重載【了解】

運(yùn)算符重載其實(shí)就是函數(shù)重寫(xiě)

代碼演示:

print(1 + 1)
print("1" + "1")
#print("1" + 1)
#不同的數(shù)據(jù)類型進(jìn)行加法運(yùn)算得到的是不同的解釋

#思考問(wèn)題:兩個(gè)對(duì)象相加畸冲?
class Person(object):
    def __init__(self,num):
        self.num = num

    def __str__(self):
        return "num=" + str(self.num)

    def __add__(self, other):
        #兩個(gè)對(duì)象相加得到的結(jié)果仍然為一個(gè)對(duì)象
        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è)計(jì)模式【擴(kuò)展】

1.概念

什么是設(shè)計(jì)模式

? 經(jīng)過(guò)已經(jīng)總結(jié)好的解決問(wèn)題的方案

? 23種設(shè)計(jì)模式观腊,比較常用的是單例設(shè)計(jì)模式邑闲,工廠設(shè)計(jì)模式,代理模式梧油,裝飾模式

什么是單例設(shè)計(jì)模式

? 單個(gè)實(shí)例【對(duì)象】

? 在程序運(yùn)行的過(guò)程中苫耸,確保某一個(gè)類只能有一個(gè)實(shí)例【對(duì)象】,不管在哪個(gè)模塊中獲取對(duì)象儡陨,獲取到的都是同一個(gè)對(duì)象

? 單例設(shè)計(jì)模式的核心:一個(gè)類有且僅有一個(gè)實(shí)例褪子,并且這個(gè)實(shí)例需要應(yīng)用在整個(gè)工程中

2.應(yīng)用場(chǎng)景

實(shí)際應(yīng)用:數(shù)據(jù)庫(kù)連接池操作-----》應(yīng)用程序中多處需要連接到數(shù)據(jù)庫(kù)------》只需要?jiǎng)?chuàng)建一個(gè)連接池即可,避免資源的浪費(fèi)

3.實(shí)現(xiàn)

3.1模塊

Python的模塊就是天然的單例設(shè)計(jì)模式

模塊的工作原理:

? import xxx,模塊被第一次導(dǎo)入的時(shí)候骗村,會(huì)生成一個(gè).pyc文件嫌褪,當(dāng)?shù)诙螌?dǎo)入的時(shí)候,會(huì)直接加載.pyc文件胚股,將不會(huì)再去執(zhí)行模塊源代碼

3.2使用new【掌握】
__new__():實(shí)例從無(wú)到有的過(guò)程【對(duì)象的創(chuàng)建過(guò)程】

代碼演示:

class Singleton(object):
    #類屬性
    instance = None

    #類方法
    @classmethod
    def __new__(cls, *args, **kwargs):
        #如果instance的值不為None笼痛,說(shuō)明已經(jīng)被實(shí)例化了,則直接返回琅拌;如果為NOne缨伊,則需要被實(shí)例化
        if not cls.instance:
            cls.instance = super(Singleton,cls).__new__(*args, **kwargs)

        return cls.instance

class MyClass(Singleton):
    pass

#當(dāng)創(chuàng)建對(duì)象的時(shí)候自動(dòng)被調(diào)用
one = MyClass()
two = MyClass()

print(id(one))
print(id(two))

print(one is two)
3.3裝飾器【掌握】

代碼演示:

#單例類:將裝飾器作用于一個(gè)類上
def singleton(cls):
    #類屬性
    instance = {}

    #成員方法
    def getSingleton(*args, **kwargs):
        #思路:如果cls在字典中,則直接返回进宝;如果不存在刻坊,則cls作為key,對(duì)象作為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.聲明一個(gè)變量【類屬性】
    instance = None

    #2.向外界提供一個(gè)公開(kāi)的方法谭胚,用于返回當(dāng)前類唯一的對(duì)象
    #方法命名格式:defaultInstance,currentInstance ,getInstance
    @classmethod
    def getInstance(cls):
        if cls.instance:
            return cls.instance
        else:
            #實(shí)例化
            cls.instance = cls()
            return  cls.instance

obj1 = Foo.getInstance()
obj2 = Foo.getInstance()

print(id(obj1) == id(obj2))
print(obj1 is obj2)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末徐块,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子灾而,更是在濱河造成了極大的恐慌胡控,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绰疤,死亡現(xiàn)場(chǎng)離奇詭異铜犬,居然都是意外死亡舞终,警方通過(guò)查閱死者的電腦和手機(jī)轻庆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)敛劝,“玉大人余爆,你說(shuō)我怎么就攤上這事】涿耍” “怎么了蛾方?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)上陕。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么洒擦? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任洒试,我火速辦了婚禮,結(jié)果婚禮上庶溶,老公的妹妹穿的比我還像新娘煮纵。我一直安慰自己,他們只是感情好偏螺,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布行疏。 她就那樣靜靜地躺著,像睡著了一般套像。 火紅的嫁衣襯著肌膚如雪酿联。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,562評(píng)論 1 305
  • 那天夺巩,我揣著相機(jī)與錄音货葬,去河邊找鬼。 笑死劲够,一個(gè)胖子當(dāng)著我的面吹牛震桶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播征绎,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蹲姐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼磨取!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起柴墩,我...
    開(kāi)封第一講書(shū)人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤忙厌,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后江咳,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體逢净,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年歼指,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了爹土。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡踩身,死狀恐怖胀茵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情挟阻,我是刑警寧澤琼娘,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站附鸽,受9級(jí)特大地震影響脱拼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜坷备,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一熄浓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧击你,春花似錦玉组、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至鸿摇,卻和暖如春石景,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拙吉。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工潮孽, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人筷黔。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓往史,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親佛舱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子椎例,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容