面向对象之多态,多态性,反射,以及基于反射的可拔插设计
多态
一、什么多态?
多态指的是一类事物有多种形态,比如
动物有多种形态:人,狗,猪
例如
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!