1、引子:isinstance(obj,cls)和issubclass(sub,super)
isinstance(obj,cls)检查是否obj是否是类 cls 的对象
class Foo: pass obj = Foo() print(isinstance(obj,Foo))
issubclass(sub, super)检查sub类是否是 super 类的派生类
class Foo: pass class Bar(Foo): pass print(issubclass(Bar,Foo))
2、什么是反射
面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
对象的反射
class People: coutury='China' def __init__(self,name): self.name=name def walk(self): print('%s is walking'%self.name) p1=People('hjc') print(p1) # print(People.coutury) # print(p1.coutury) # print(People.__dict__) # hasattr 判断这个对象有没有响应的属性 # print('name' in p1.__dict__) # 相当下面 # print(hasattr(p1,'name')) # 判断这个 name 属性在不在这个对象的 dict 里面 # print(hasattr(p1,'coutury')) # print(hasattr(p1,'__init__')) # getattr 调用对象中存在的属性 res=getattr(p1,'coutury') # 相当于 res=p1.coutury=China print(res) # 对象.属性,这里 coutury 是对象的数据属性 res1=getattr(People,'walk') # 相当于 res1=People.walk=一个函数的内存地址 print(res1) # 类名.属性,这里 walk 是类的函数 res2=getattr(p1,'walk') # 相当于 res2=p1.walk=一个绑定方法的内存地址 print(res2) # 对象.属性,这里 walk 是对象的绑定方法 res2() # 相当于 res2()=p1.walk(p1) 绑定方法自动把对象传值 res1(p1) # 相当于 res1()=People.walk(p1) 函数手动把对象传值 res3=getattr(p1,'xxxxx','这个属性不存在') # 如果属性不存在,可以给个提示 print(res3) # 用法,可以用来判断属性存不存在,存在就执行,不存在就过 if hasattr(p1,'walk'): func=getattr(p1,'walk') func() print('-------') # setattr p1.sex='male' print(p1.sex) setattr(p1,'age',18) # 通过 setattr 可以对对象进行设置属性,格式:对象,'属性','值' print(p1.__dict__) # 查看有没有到 对象里面去 print(p1.age) print(getattr(p1,'age')) # 取 setattr 设置的值 # delattr print(p1.__dict__) del p1.sex # 删除对象属性的第一种方法 print(p1.__dict__) delattr(p1,'age') # 删除对象属性的第二种方法 print(p1.__dict__)
模块的反射
import sys class foo: pass def s1(): pass def s2(): pass this_module=sys.modules[__name__] print(this_module) # 一个模块的对象 print(hasattr(this_module,'s1')) # 查看方式跟对象的反射一样 print(getattr(this_module,'s2')) # 只不过对象是模块 print(getattr(this_module,'foo')) print(this_module.foo) print(this_module.s1)
类的反射
class Foo: f = 123 @classmethod def class_method_dome(cls): print('class_method_dome') @staticmethod def static_method_dome(): print('static_method_dome')
print(hasattr(Foo,'class_method_dome')) method = getattr(Foo,'class_method_dome') method() print('------------') print(hasattr(Foo,'static_method_dome')) method1 = getattr(Foo,'static_method_dome') method1()
3、为什么用反射?
实现可插拔机制
有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。
总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能
ftpclient.py class FtpClient: 'ftp客户端,但是还么有实现具体的功能' def __init__(self,addr): print('正在连接服务器[%s]' %addr) self.addr=addr ftpserver.py from ftpclient import FtpClient f1=FtpClient('192.168.1.1') if hasattr(f1,'get'): func_get=getattr(f1,'get') func_get() else: print('---->不存在此方法') print('处理其他的逻辑')