DAY34 多態與多態性、綁定方法和非綁定方法

多態與多態性

多態

多態並不是一個新的知識

多態是指一類事物有多種形態,在類裏就是指一個抽象類有多個子類,因而多態的概念依賴於繼承

舉個栗子:動物有多種形態,人、狗、貓、豬等,python的序列數據類型有字符串、列表、元組,文件的類型分爲普通文件和可執行文件,人類又有多種形態,男女老少。。等等例子

import abc
class Animal(metaclass=abc.ABCMeta):    #模擬動物類
    @abc.abstractmethod
    def talk(self):
        pass
class People(Animal):       #模擬人類
    def talk(self):
        print('say hello world')
class Cat(Animal):          #模擬貓類
    def talk(self):
        print('say miaomiaomiao')
class Dog(Animal):          #模擬狗類
    def talk(self):
        print('say wangwangwang')

動物都能叫,所以人類、貓類、狗類也都可以叫,只不過叫的方式不一樣。

多態性:

多態性是指具有不同功能的函數可以使用相同的函數名,這樣就可以用一個函數名調用到不同功能的函數。

在面向對象方法中一般是這樣表述多態性:向不同的對象發送同一條消息(!!!obj.func():是調用了obj的方法func,又稱爲向obj發送了一條消息func),不同的對象在接收時會產生不同的行爲(即方法)

多態性實際上就是一個接口,即調用同一個函數,產生不同的結果。

示例1:使用數據對象的len屬性統計對象長度

1 def func(obj):
2     obj.__len__()
3 func('hello')
4 func([1,2,3,4])
5 func(('a','b','c'))

示例2:

import abc
class Animal(metaclass=abc.ABCMeta):    #模擬動物類
    @abc.abstractmethod
    def talk(self):
        pass
class People(Animal):       #模擬人類
    def talk(self):
        print('say hello world')
class Cat(Animal):          #模擬貓類
    def talk(self):
        print('say miaomiaomiao')
class Dog(Animal):          #模擬狗類
    def talk(self):
        print('say wangwangwang')

p1=People()
c1=Cat()
d1=Dog()

def talk(obj):    #多態性
    obj.talk()
talk(p1)
talk(c1)
talk(d1)

多態性的優點1:以不變應萬變,統一調用接口,使用者只用一種調用方式即可

多態性的優點2:增加擴展性,比如上述代碼再加一個Pig類,調用talk功能的方式不會改變,就是talk(Pig對象)

綁定方法與非綁定方法

類中定義的函數分爲兩類:綁定方法和非綁定方法

綁定方法:綁定給誰就給誰用,可以是對象,也可以是類本身。

綁定到對象的方法:

  定義:凡是在類中定義的函數(沒有被任何裝飾器修飾),都是綁定給對象的,無論有有沒有傳參

  給誰用:給對象用

  特點:例如obj.bar() 自動把obj當做第一個參數傳入,因爲bar中的邏輯就是要處理obj這個對象

示例:

class People:
    def __init__(self, name, weight, height):
        self.name = name
        self.weight = weight
        self.height = height
    def bmi(self):    #綁定到對象,需要傳入對象的名字,而類本身是無法使用的,如果硬要使用,也需要把對象名字傳進來
        print(self.weight / (self.height ** 2))
f = People('bob', 70, 1.80)
f.bmi()    #綁定對象使用的方法
People.bmi(f)    #類使用需要傳入對象名字

綁定到類的方法:
定義:在類中定義的,被classmethod裝飾的函數就是綁定到類的方法

  給誰用:給類用

  特點:例如People.talk() 自動把類當做第一個參數傳入,因爲talk中的邏輯就是要處理類

注意:自動傳值只是使用者意淫的,屬於類的函數,類可以調用,但是必須按照函數的規則來,在任何過程中都沒有自動傳值那麼一說,傳值都是事先定義好的,只不過使用者感知不到。

示例1:

class People:
    def __init__(self,name):
        self.name=name
    def bar(self):
        print('Object name:',self.name)
    @classmethod    #將方法綁定給類People
    def func(cls):  #傳入的值只能是類的名字
        print('Class name:',cls)
f=People('natasha')
print(People.func)  #綁定給類
print(f.bar)    #綁定給對象
People.func()   #類調用綁定到類的方法
f.func()    #對象調用綁定到類的方法,打印的依然是類的名字

輸出結果:

<bound method People.func of <class '__main__.People'>>    #綁定到類的方法
<bound method People.bar of <__main__.People object at 0x0000026FC4109B38>>    #綁定到對象的方法
Class name: <class '__main__.People'>     #類調用返回類名
Class name: <class '__main__.People'>     #對象調用返回類名

非綁定方法:

用staticmethod裝飾器裝飾的方法,非綁定方法不與類或對象綁定,類和對象都可以調用,但是沒有自動傳值那麼一說。就是一個普通工具而已

注意:沒有傳值的普通函數並不是非綁定方法,只有被staticmethod裝飾的纔是非綁定方法。

示例

import hashlib
import pickle
import os
# 模擬註冊,生成一個唯一id標識
student_path=r'C:\Users\Mr.chai\Desktop\PythonProject\筆記\2017.7.6\db'

class People:
    def __init__(self,name,sex,user_id):
        self.name=name
        self.sex=sex
        self.user_id=user_id
        self.id=self.create_id()
    def tell_info(self):    #打印所有信息
        print('''
        =====%s info=====
        id:%s
        name:%s
        sex:%s
        user_id:%s
        ''' %(self.name,self.id,self.name,self.sex,self.user_id))
    def create_id(self):    #生成一個id號,對name、sex和user_id進行哈希
        m=hashlib.md5()
        m.update(self.name.encode('utf-8'))
        m.update(self.sex.encode('utf-8'))
        m.update(str(self.user_id).encode('utf-8'))
        return m.hexdigest()
    def save(self):     #將id號序列化到文件,以id號爲文件名字
        idfile_path=student_path+'\\'+self.id
        with open(idfile_path,'wb') as f:
            pickle.dump(self,f)
    @staticmethod       #反序列化程序,是一個非綁定方法,無關類和對象
    def get_all():
        res=os.listdir(student_path)
        for item in res:
            file_path = r'%s\%s' %(student_path,item)
            with open(file_path,'rb') as f:
                obj = pickle.load(f)
                obj.tell_info()

測試:生成序列化文件

#實例化對象
p1=People('natasha','male',370283111111111111)
p2=People('hurry','male',3702832222222222222)
p3=People('bob','male',3702833333333333333)
#查詢唯一標識
print(p1.id)
print(p2.id)
print(p3.id)
#對象pickle序列化
p1.save()
p2.save()
p3.save()

查詢輸出:
b4ea1e1f1e45428ee16035e101caac7b
274496ab60ceea8bf4c89c841d2b225c17 0defdb74fdee00f2164839343c16a7d7

生成文件

這裏寫圖片描述
反序列化:

p1.get_all()
# p2.get_all()
# p3.get_all()

輸出結果

        =====bob info=====
        id:0defdb74fdee00f2164839343c16a7d7
        name:bob
        sex:male
        user_id:3702833333333333333


        =====hurry info=====
        id:274496ab60ceea8bf4c89c841d2b225c
        name:hurry
        sex:male
        user_id:3702832222222222222


        =====natasha info=====
        id:b4ea1e1f1e45428ee16035e101caac7b
        name:natasha
        sex:male
        user_id:370283111111111111
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章