1. 程式人生 > >編程之路:多態和綁定與非綁定方法

編程之路:多態和綁定與非綁定方法

SM 可執行文件 bst sql 走起 view ont 們的 self

多態

多態是指一類事物有多種形態

動物有多種形態:人、狗、豬

import abc
class Animal(metaclass=abc.ABCMeta): #同一類事物:動物
    @abc.abstractmethod
    def talk(self):
        pass

class People(Animal): #動物的形態之一:人
    def talk(self):
        print(‘say hello‘)

class Dog(Animal): #動物的形態之二:狗
    def talk(self):
        print(‘say wangwang‘)

class Pig(Animal): #動物的形態之三:豬
    def talk(self):
        print(‘say aoao‘)

文件有多種形態:文本文件,可執行文件

import abc
class File(metaclass=abc.ABCMeta): #同一類事物:文件
    @abc.abstractmethod
    def click(self):
        pass

class Text(File): #文件的形態之一:文本文件
    def click(self):
        print(‘open file‘)

class ExeFile(File): #文件的形態之二:可執行文件
    def click(self):
        print(‘execute file‘)

多態性

可以在不用考慮對象具體類型的前提下而直接使用對象下的方法

技術分享圖片
在面向對象方法中一般是這樣表述多態性:向不同的對象發送同一條消息(!!!obj.func():是調用了obj的方法func,又稱為向obj發送了一條消息func),不同的對象在接收時會產生不同的行為(即方法)。也就是說,每個對象可以用自己的方式去響應共同的消息。所謂消息,就是調用函數,不同的行為就是指不同的實現,即執行不同的函數。

比如:老師.下課鈴響了(),學生.下課鈴響了(),老師執行的是下班操作,學生執行的是放學操作,雖然二者消息一樣,但是執行的效果不同
View Code

多態性分為靜態多態性和動態多態性

  靜態多態性:如任何類型都可以用運算符+進行運算

  動態多態性:如下

peo=People()
dog=Dog()
pig=Pig()

#peo、dog、pig都是動物,只要是動物肯定有talk方法
#於是我們可以不用考慮它們三者的具體是什麽類型,而直接使用
peo.talk()
dog.talk()
pig.talk()

#更進一步,我們可以定義一個統一的接口來使用
def func(obj):
    obj.talk()

為什麽要用多態性(多態性的好處)

其實大家從上面多態性的例子可以看出,我們並沒有增加什麽新的知識,也就是說python本身就是支持多態性的,這麽做的好處是什麽呢?

1.增加了程序的靈活性

  以不變應萬變,不論對象千變萬化,使用者都是同一種形式去調用,如func(animal)

2.增加了程序額可擴展性

  通過繼承animal類創建了一個新的類,使用者無需更改自己的代碼,還是用func(animal)去調用     

>>> class Cat(Animal): #屬於動物的另外一種形態:貓
...     def talk(self):
...         print(‘say miao‘)
... 
>>> def func(animal): #對於使用者來說,自己的代碼根本無需改動
...     animal.talk()
... 
>>> cat1=Cat() #實例出一只貓
>>> func(cat1) #甚至連調用方式也無需改變,就能調用貓的talk功能
say miao

‘‘‘
這樣我們新增了一個形態Cat,由Cat類產生的實例cat1,使用者可以在完全不需要修改自己代碼的情況下。使用和人、狗、豬一樣的方式調用cat1的talk方法,即func(cat1)
‘‘‘

鴨子類型

逗比時刻:

  Python崇尚鴨子類型,即‘如果看起來像、叫聲像而且走起路來像鴨子,那麽它就是鴨子’

python程序員通常根據這種行為來編寫程序。例如,如果想編寫現有對象的自定義版本,可以繼承該對象

也可以創建一個外觀和行為像,但與它無任何關系的全新對象,後者通常用於保存程序組件的松耦合度。

例1:利用標準庫中定義的各種‘與文件類似’的對象,盡管這些對象的工作方式像文件,但他們沒有繼承內置文件對象的方法

技術分享圖片
#二者都像鴨子,二者看起來都像文件,因而就可以當文件一樣去用
class TxtFile:
    def read(self):
        pass

    def write(self):
        pass

class DiskFile:
    def read(self):
        pass
    def write(self):
        pass
View Code

例2:其實大家一直在享受著多態性帶來的好處,比如Python的序列類型有多種形態:字符串,列表,元組,多態性體現如下

技術分享圖片
#str,list,tuple都是序列類型
s=str(hello)
l=list([1,2,3])
t=tuple((4,5,6))

#我們可以在不考慮三者類型的前提下使用s,l,t
s.__len__()
l.__len__()
t.__len__()

len(s)
len(l)
len(t)
View Code

類中定義的函數分成兩大類

一:綁定方法(綁定給誰,誰來調用就自動將它本身當作第一個參數傳入):

    1. 綁定到類的方法:用classmethod裝飾器裝飾的方法。

為類量身定制

類.boud_method(),自動將類當作第一個參數傳入

(其實對象也可調用,但仍將類當作第一個參數傳入)

    2. 綁定到對象的方法:沒有被任何裝飾器裝飾的方法。

為對象量身定制

對象.boud_method(),自動將對象當作第一個參數傳入

(屬於類的函數,類可以調用,但是必須按照函數的規則來,沒有自動傳值那麽一說)

二:非綁定方法:用staticmethod裝飾器裝飾的方法

   1. 不與類或對象綁定,類和對象都可以調用,但是沒有自動傳值那麽一說。就是一個普通工具而已

    註意:與綁定到對象方法區分開,在類中直接定義的函數,沒有被任何裝飾器裝飾的,都是綁定到對象的方法,可不是普通函數,對象調用該方法會自動傳值,而staticmethod裝飾的方法,不管誰來調用,都沒有自動傳值一說

綁定方法

綁定給對象的方法(略)

綁定給類的方法(classmethod)

  classmehtod是給類用的,即綁定到類,類在使用時會將類本身當做參數傳給類方法的第一個參數(即便是對象來調用也會將類當作第一個參數傳入),python為我們內置了函數classmethod來把類中的函數定義成類方法

技術分享圖片
HOST=127.0.0.1
PORT=3306
DB_PATH=rC:\Users\Administrator\PycharmProjects\test\面向對象編程\test1\db
View Code
import settings
class MySQL:
    def __init__(self,host,port):
        self.host=host
        self.port=port

    @classmethod
    def from_conf(cls):
        print(cls)
        return cls(settings.HOST,settings.PORT)

print(MySQL.from_conf) #<bound method MySQL.from_conf of <class ‘__main__.MySQL‘>>
conn=MySQL.from_conf()

conn.from_conf() #對象也可以調用,但是默認傳的第一個參數仍然是類

非綁定方法

在類內部用staticmethod裝飾的函數即非綁定方法,就是普通函數

statimethod不與類或對象綁定,誰都可以調用,沒有自動傳值效果

import hashlib
import time
class MySQL:
    def __init__(self,host,port):
        self.id=self.create_id()
        self.host=host
        self.port=port
    @staticmethod
    def create_id(): #就是一個普通工具
        m=hashlib.md5(str(time.time()).encode(‘utf-8‘))
        return m.hexdigest()


print(MySQL.create_id) #<function MySQL.create_id at 0x0000000001E6B9D8> #查看結果為普通函數
conn=MySQL(‘127.0.0.1‘,3306)
print(conn.create_id) #<function MySQL.create_id at 0x00000000026FB9D8> #查看結果為普通函數

classmethod與staticmethod的區別

技術分享圖片
import settings
class MySQL:
    def __init__(self,host,port):
        self.host=host
        self.port=port

    @staticmethod
    def from_conf():
        return MySQL(settings.HOST,settings.PORT)

    # @classmethod #哪個類來調用,就將哪個類當做第一個參數傳入
    # def from_conf(cls):
    #     return cls(settings.HOST,settings.PORT)

    def __str__(self):
        return 就不告訴你

class Mariadb(MySQL):
    def __str__(self):
        return <%s:%s> %(self.host,self.port)


m=Mariadb.from_conf()
print(m) #我們的意圖是想觸發Mariadb.__str__,但是結果觸發了MySQL.__str__的執行,打印就不告訴你:

mariadb是mysql
View Code

編程之路:多態和綁定與非綁定方法