什么是反射
反射就是通过字符串的形式,导入模块;通过字符串的形式,去模块寻找指定函数,并执行。利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员,一种基于字符串的事件驱动!
python 里的反射有下面四种方法
- hasattr(obj,name_str):判断一个对象 obj 里是否有对应的 name_str 字符串的方法
- getattr(obj,name_str):根据字符串去获取 obj 对象里的对应方法的内存地址
- setattr(obj,"y",z):相当于 obj.y=z
- delattr(obj,name_str):删除属性
命名空间.XXX == getattr(命名空间,"XXX")
类名.名字
- getattr(类名,"名字")
对象名.名字
- getattr(对象,"名字")
模块名.名字
- import 模块
- getattr(模块,”名字“)
自己文件.名字
- import sys
- getattr(sys.modules['__main__'],"名字")
类,静态属性,类方法,静态方法都可以反射
class Student: ROLE = 'STUDENT' @classmethod def check_course(cls): print('查看课程了') @staticmethod def login(): print('登录') print(Student.ROLE) print(getattr(Student, 'ROLE')) # 反射查看属性 # 反射调用方法 getattr(Student, 'check_course')() # 类方法 getattr(Student, 'login')() # 静态方法
结果:
STUDENT STUDENT 查看课程了 登录
hasattr和getattr
class Dog(object): def __init__(self, name): self.name = name def eat(self, food): print('%s is eating...' % self.name, food) d = Dog('张三') choice = input('请输入>>:').strip() # 不能d.choice() 会报错,因为choice是字符串 print(hasattr(d, choice)) # 判断输入的在类里有没有这个方法,有返回True,否则False print(getattr(d, choice)) # 返回了输入方法的内存对象 getattr(d, choice)('鸡蛋') # 知道内存对象后加()传参调用
用户输入 eat 时,因为 Dog 类下有 eat 方法
请输入>>:eat True <bound method Dog.eat of <__main__.Dog object at 0x038D2070>> 张三 is eating... 鸡蛋
在输入 Dog 类下不存在的。比如 game
请输入>>:game False Traceback (most recent call last): File "E:/git_test1/djago_DRF/DRFApi/apps/mtauth/tests.py", line 16, in <module> print(getattr(d, choice)) # 返回了输入方法的内存对象 AttributeError: 'Dog' object has no attribute 'game'
因为Dog下没有 game ,所以报错了
所以可以做个判断,如果 hasattr(d, choice) 返回为 True了,在执行 getattr(d, choice)
改写后的如下
class Dog(object): def __init__(self, name): self.name = name def eat(self, food): print('%s is eating...' % self.name, food) d = Dog('张三') choice = input('请输入>>:').strip() if hasattr(d, choice): # 判断输入的在类里有没有这个方法 func = getattr(d, choice) # 有这个方法执行,获得输入 的在类里方法的内存对象 func('鸡蛋') # 将参数传给func,相当于执行d.eat('鸡蛋')
在输入 eat
请输入>>:eat 张三 is eating... 鸡蛋
输入 game
setattr
看如下例子
def bulk(self): # 装到类里必须要有self print('%s in the bulking...' % self.name) class Dog(object): def __init__(self, name): self.name = name def eat(self, food): print('%s is eating...' % self.name, food) d = Dog('张三') choice = input('请输入>>:').strip() if hasattr(d, choice): # 判断输入的在类里有没有这个方法 func = getattr(d, choice) # 有这个方法执行,获得输入的在类里方法的内存对象 func('鸡蛋') # 将参数传给func,相当于执行了d.eat('鸡蛋') else: # 输入的类里面的方法里没有 setattr(d, choice, bulk) # 等价于d.choice=bulk,动态加了个方法 d.talk(d) # 执行输入的,相当于执行了bulk,要把类对象传给,必须是d.输入的内容
输入 eat 时
请输入>>:eat 张三 is eating... 鸡蛋
输入不存在的 game 时
当输入 talk 时
这时用户只能输入 eat 或者 talk ,输入其他会报错
如果想让输入 Dog类下不存在的方法,都执行 talk 下的,就可以这样写
def bulk(self): # 装到类里必须要有self print('%s in the bulking...' % self.name) class Dog(object): def __init__(self, name): self.name = name def eat(self, food): print('%s is eating...' % self.name, food) d = Dog('张三') choice = input('>>:').strip() if hasattr(d, choice): func = getattr(d, choice) # 有这个方法执行,获得输入的在类里方法的内存对象 func('鸡蛋') # 将参数传给func,相当于执行了d.eat('鸡蛋') else: # 输入的类里面的方法里没有 setattr(d, choice, bulk) # 等价于d.choice=bulk,动态加了个方法 func = getattr(d, choice) # 获得新加方法的内存对象 func(d) # 调用新加的方法,不管输入什么,都执行的是bulk里的
输入 eat
>>:eat 张三 is eating... 鸡蛋
输入 game
>>:game 张三 in the bulking...