面向对象之多态,多态性,反射,以及基于反射的可拔插设计

时间:2021-09-22 21:56:06

多态

什么多态?

多态指的是一类事物有多种形态,比如
动物有多种形态:人,狗,猪

>>例如
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!