Python多態(tài)

一、多態(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)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容