一、反射的定义
反射是根据命名空间,通过变量名或者方法名的字符串形式来判断、查找、修改或者删除对应的值或者返回值
格式为:has/get/set/delattr(命名空间, 字符串形式的变量名/方法名)
'''案例类'''
class Student:
ROLE = 'student'
@classmethod
def check_course(cls):
print("检查课程")
def choose_course(self):
print("选择课程")
def choosed_course(self):
print("以选择的课程")
@staticmethod
def login(username, password):
if username == '李镇' and password == '1234':
print('登陆成功')
else:
print('登陆失败')
class Level(Student):
pass
二、判断变量或者方法是否存在
- 判断是否存在
i = 0
while 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本质上是一个函数
i
import os
rename = 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 = name
a = A('李志')
setattr(a, 'name', '刘欢')
# setattr中的三个参数:第一个是命名空间/内存空间,第二个是需要被修改的变量/方法名,第三个是替换的内容
print(a.name)
# 结果是:刘欢
五、反射删除内容
- 反射删除内容的基本格式:delattr(命名空间, 需要被删除的变量名/方法)
class A:
def __init__(self, name):
self.name = name
def func(self):
print(self, '类的内存地址')
'''删除属性delattr()'''
delattr(a, 'name')
# print(a.name)
# 删除类中的属性
delattr(a, 'func')
getattr(a, 'func')()
# 删除类中方法
六、综合利用反射,创建简单的教务管理系统
import sys
class Teacher:
operate_list = [('打印教师信息', 'func'), ]
# 把方法和提示信息作为元组组成一个方法信息列表
def __init__(self, name):
self.name = name
def func(self):
print('教师')
@classmethod
def status_attr(cls):
return cls.operate_list
class Student:
operate_list = [('查看课程', 'check_course'), ('选择课程', 'choose_course')]
def __init__(self, name):
self.name = name
def check_course(self):
print('查看课程')
def choose_course(self):
print("请选择课程")
@classmethod
def status_attr(cls):
return cls.operate_list
class Manager:
operate_list = [('创建学生信息','create_student'), ('创建课程', 'create_course'), ('查看学生信息', 'check_student_info')]
def __init__(self, name):
self.name = name
def create_student(self):
print('创建学生对象')
def create_course(self):
print('创建课程')
def check_student_info(self):
print('核对学生对象')
@classmethod
def status_attr(cls):
return cls.operate_list
def 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 sys
def main():
global i
file = 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()