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

多态

一、什么多态?

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

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!
原文地址:https://www.cnblogs.com/zjcode/p/8718596.html