1. 程式人生 > >面向對象之多態,多態性,反射,以及基於反射的可拔插設計

面向對象之多態,多態性,反射,以及基於反射的可拔插設計

it is sat pass ict method func let HA strac

多態

什麽多態?

多態指的是一類事物有多種形態,比如
動物有多種形態:人,狗,豬

>>例如
import abc  #創建抽象類 導入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')

多態性

1.什麽是多態性

多態性是指在不考慮實例類型的情況下使用實例,多態性分為 靜態多態性 和 動態多態性

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

動態多態性如下實例:

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

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

#更進一步,我們可以定義一個統一的接口來使用,動態的執行不同動物的talk方法
def func(obj):
    obj.talk()

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

1.增加了程序的靈活性>>>
  以不變應萬變,不論對象千變萬化,使用者都是同一種形式去調用,如func(animal)

2.增加了程序額可擴展性>>>
 通過繼承animal類創建了一個新的類,使用者無需更改自己的代碼,還是用func(animal)去調用
class H2O: #水有多種形態冰,液態水,水蒸氣
def init(self, name, temp):
self.name = name
self.temp = temp

def turn_active(self):
    if self.temp < 0:
        print("我是 %s 我已經變成冰了!" % self.name)
    elif self.temp > 0 and self.temp < 100:
        print("我是液水")
    elif self.temp > 100:
        print("我是%s 我變成水蒸氣了" % self.name)


class Water(H2O):
    pass


class Iire(H2O):
    pass


class Vapor(H2O):
    pass


w1 = Water('水', 10) #生成各自的實例
i1 = Iire("冰", -100)
v1 = Vapor("水蒸氣", 1000)


# ************
def func(obj): ##對於使用者來說,自己的代碼根本無需改動
    obj.turn_active()


func(w1) #實例調用統一的接口來實行trun_active()方法

二 反射

1.什麽反射:

反射的概念是由Smith在1982年首次提出的,主要是指程序可以訪問、檢測和修改它本身狀態或行為的一種能力(自省)。這一概念的提出很快引發了計算機科學領域關於應用反射性的研究。它首先被程序語言的設計領域所采用,並在Lisp和面向對象方面取得了成績。

2.python面向對象中的反射:

通過字符串的形式操作對象相關的屬性。python中的一切事物都是對象(都可以使用反射)

四個可以實現自省的函數 下列方法適用於類和對象(一切皆對象,類本身也是一個對象)[hasattr,getattr,setattr,delattr]

hasattr(object,name)

判斷object中有沒有一個name字符串對應的方法或屬性

getattr(object, name, default=None)

獲取對象的屬性方法(Get a named attribute from an object)

    def getattr(object, name, default=None): # known special case of getattr
        """
        getattr(object, name[, default]) -> value
    
        Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
        When a default argument is given, it is returned when the attribute doesn't
        exist; without it, an exception is raised in that case.
        """
        pass

setattr(x, y, v)

def setattr(x, y, v): # real signature unknown; restored from __doc__
"""
Sets the named attribute on the given object to the specified value.

setattr(x, 'y', v) is equivalent to ``x.y = v''
"""
pass

delattr(x, y)

def delattr(x, y): # real signature unknown; restored from __doc__
    """
    Deletes the named attribute from the given object.

    delattr(x, 'y') is equivalent to ``del x.y''
    """
    pass

四個方法的使用演示

class BlackMedium:
    feture = 'Ugly'

    def __init__(self, name, addr):
        self.name = name
        self.addr = addr

    def sell_hourse(self):
        print('【%s】 正在賣房子,傻逼才買呢' % self.name)

    def rent_hourse(self):
        print('【%s】 正在租房子,傻逼才租呢' % self.name)



b1=BlackMedium("黑中介","北京")
print(hasattr(b1,"name")) #判斷實例有沒有name的這個屬性

func=getattr(b1,"sell_hourse")# 獲得實例屬性
func()
func1=getattr(b1,"sell_hoursedasd","沒有這個屬性") # default默認值
print(func1)


setattr(b1,"key","v1") #給對應實例添加數據屬性

print(b1.__dict__)


delattr(b1,"key") #  刪除實例的屬性
print(b1.__dict__)

setattr(b1,"func2",lambda x:x+1)  #實例 設置 函數屬性

print(b1.func2(10))

三、動態導入模塊

mm為當前目錄下的文件夾下面有tt.py
m = model_t = __import__("mm.tt")  # 只能導入第一層
print(m)
m.tt.test1()

import importlib #使用模塊 動態導入,推薦這種方法
m2=importlib.import_module("mm.tt")
print(m2)
m2.test2()

四、基於反射實現可拔插組件

bob正在負責寫FTP的客戶端,但是最近他有大事,給耽誤了,並且其他人需要用到這個ftp中的一些方法,這時候我們就需要用到反射

客戶端殘次品代碼

    class FtpClient:
    def __init__(self,name):
        print("client ....")
        self.name=name

調用者需要基於反射調用FTp的客戶端,如下:

from Ftp_client import *
c1 = FtpClient("client")
if hasattr(c1, "put"): #判斷FTP客戶端有沒有put方法
    put_func = getattr(c1, "put") # 有就調用執行
    put_func()
else:
    print("沒有執行put 完成其他操作!") #沒有do other things!

面向對象之多態,多態性,反射,以及基於反射的可拔插設計