反射的用法

反射的使用

一、反射的定义

反射是根据命名空间,通过变量名或者方法名的字符串形式来判断、查找、修改或者删除对应的值或者返回值
格式为: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()

猜你喜欢

转载自www.cnblogs.com/ddzc/p/12264475.html