一、反射的定义
反射是根据命名空间,通过变量名或者方法名的字符串形式来判断、查找、修改或者删除对应的值或者返回值
格式为:has/get/set/delattr(命名空间, 字符串形式的变量名/方法名)
'''案例类'''class Student:ROLE = 'student'@classmethoddef check_course(cls):print("检查课程")def choose_course(self):print("选择课程")def choosed_course(self):print("以选择的课程")@staticmethoddef login(username, password):if username == '李镇' and password == '1234':print('登陆成功')else:print('登陆失败')class Level(Student):pass
二、判断变量或者方法是否存在
- 判断是否存在
i = 0while i <= 3:name = input('请输入方法名:')# getattr(Level, name)()# 这里获取的是方法,所以需要加上括号if hasattr(Student, name):# hasattr()判断的是是否存在属性/方法getattr(Student, name)()# 如果存在则获取else:print('方法名不存在')i += 1
三、获取对应的值或者返回值
- 反射查看属性对应的值
'''反射查看属性'''print(getattr(Student, 'ROLE'))print(getattr(Level, 'ROLE'))print(getattr(s1, 'ROLE'))# getattr()第一个参数是命名空间, 第二个参数是命名空间中变量名的字符串格式名称,获取的是变量名对应的值# 命名空间可以是类、实例化对象等
- 反射查看方法对应的返回值
'''反射查看方法'''getattr(Student, 'check_course')()# 反射调用类方法# print(getattr(Student, 'choose_course')())getattr(Student, 'login')('李镇', '1234')# 反射调用静态方法# getattr()第一个参数是命名空间, 第二个参数是命名空间中方法名的字符串格式名称,获取的是方法对应的返回值# getattr(Student, 'login')获取的只是方法对应的内存地址,需要加上括号来执行获取返回值
Note 需要注意的是:命名空间可以是类,也可以是实例化后的对象,当getattr()查看方法的时候获取到的是对应的内存空间,需要加上()才能获取到值 也可以通过子类来调用父类中的方法或者变量
- 模块中反射的使用
模块本质上还是有类组成的py文件或者类,所以模块的名即为命名空间,字符串为方法名
python模块反射案例(必须先导入使用的模块)
'''模块的反射'''# import os# getattr(os, 'rename')('t2.py', 't1.py')# # 通过模块来修改文件的名称, rename本质上是一个函数iimport osrename = os.rename# os.rename得到的是rename函数的内存地址result = getattr(os, 'rename')result = result('t2.py', 't1.py')'''模块的反射,命名空间是模块名,字符串是模块中的方法名'''
把自己写的文件当作模块,反射模块中的函数,获取结果
- 第一步:导入sys模块,获取py文件的内存地址,赋值给my_file变量,把内存地址作为getattr()的第一个参数
- 第二步:在进行getattr(my_file,’文件中的函数’)()
def func1():print("这是一个测试的程序")def func2():print("第二个程序")# func1()# func2()import sys# print(sys.modules)# print("-------------------")# print(sys.modules['__main__'])# # 这里打印的是py文件的内存地址(__main__)# my_file = sys.modules['__main__']# getattr(my_file, 'func1')()# # 把自己的py文件作为单独模块,反射文件中程序的结果my_file = sys.modules['__main__']# 先获取py文件的内存地址,这是固定格式getattr(my_file, 'func2')()# getattr()的第一个参数就是命名空间,也就是内存地址# 根据内存地址来调取函数,获取的是文件中函数的内存地址,在加括号执行函数返回结果
四、反射并修改内容
- 修改内容的基本格式:setattr(命名空间, 变量名/方法名,替换内容)
'''修改属性setattr()'''class A:def __init__(self, name):self.name = namea = A('李志')setattr(a, 'name', '刘欢')# setattr中的三个参数:第一个是命名空间/内存空间,第二个是需要被修改的变量/方法名,第三个是替换的内容print(a.name)# 结果是:刘欢
五、反射删除内容
- 反射删除内容的基本格式:delattr(命名空间, 需要被删除的变量名/方法)
class A:def __init__(self, name):self.name = namedef func(self):print(self, '类的内存地址')'''删除属性delattr()'''delattr(a, 'name')# print(a.name)# 删除类中的属性delattr(a, 'func')getattr(a, 'func')()# 删除类中方法
六、综合利用反射,创建简单的教务管理系统
import sysclass Teacher:operate_list = [('打印教师信息', 'func'), ]# 把方法和提示信息作为元组组成一个方法信息列表def __init__(self, name):self.name = namedef func(self):print('教师')@classmethoddef status_attr(cls):return cls.operate_listclass Student:operate_list = [('查看课程', 'check_course'), ('选择课程', 'choose_course')]def __init__(self, name):self.name = namedef check_course(self):print('查看课程')def choose_course(self):print("请选择课程")@classmethoddef status_attr(cls):return cls.operate_listclass Manager:operate_list = [('创建学生信息','create_student'), ('创建课程', 'create_course'), ('查看学生信息', 'check_student_info')]def __init__(self, name):self.name = namedef create_student(self):print('创建学生对象')def create_course(self):print('创建课程')def check_student_info(self):print('核对学生对象')@classmethoddef status_attr(cls):return cls.operate_listdef login():with open('userinfo.txt', mode='r', encoding='utf-8') as f:username = input('请输入用户名:')password = input('请输入密码:')# 提示用户输入用户名和密码for line in f:line = line.rstrip('\n')user, pwd, ident = line.split('|')# 从文件中读取用户名、密码和身份信息if user == username and pwd == password:print("登陆成功")return username, ident# 判断信息是否一致,一致返回用户名和身份# 程序的入口import sysdef main():global ifile = sys.modules['__main__']# 获取文件所在的内存空间地址,需要用sys模块user, ident = login()# 接收信息if hasattr(file, ident):# 注意:文件中的ident和程序中的类名是完全一样的,所以可以把ident作为类名来使用obj = getattr(file, ident)(user)# 获取类的内存地址,并实例化对象print(obj.name)operate_list = getattr(obj, 'operate_list')# 反射类中的静态字段for num, i in enumerate(operate_list, 1):print(num, i[0])# 利用枚举获取静态字段信息,序号和信息共同组成,enuerate(可迭代对象, 设定的第一个序号值)while True:num = int(input("请输入选项序号:"))choose_name = operate_list[num - 1][1]# 提示用户输入需要,根据序号找到方法对应的提示信息getattr(obj, choose_name)()# 再根据信息找到对应的方法,并反射内容# getattr(operate_list, i[num - 1])main()
