• python--反射


    什么是反射

    反射就是通过字符串的形式,导入模块;通过字符串的形式,去模块寻找指定函数,并执行。利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员,一种基于字符串的事件驱动!

    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...

    delattr

    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):
        delattr(d, choice)  # 删除属性,
    
    else:  # 输入的类里面的方法里没有
        setattr(d, choice, bulk)  # 等价于d.choice=bulk,动态加了个方法
        d.talk(d)  # 执行输入的,相当于执行了bulk,要把类对象传给,必须是d.输入的内容
    print(d.name)  

    输入name

    输入name,最后打印报错,因为属性name已经被删除了

    反射应用的例子

    import sys
    
    
    class Manager:
        OPERATE_DIC = [
            ('创造学生账号', '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('查看学生信息')
    
    
    class Student:
        OPERATE_DIC = [
            ('查看所有课程', 'check_course'),
            ('选择课程', 'choose_course'),
            ('查看已选择的课程', 'choosed_course')
        ]
    
        def __init__(self, name):
            self.name = name
    
        def check_course(self):
            print('check_course')
    
        def choose_course(self):
            print('choose_course')
    
        def choosed_course(self):
            print('查看已选择的课程')
    
    
    def login():
        username = input('请输入user : ')
        password = input('请输入pwd : ')
        with open('user_info') as f:
            for line in f:
                user, pwd, ident = line.strip().split('|')  # ident = 'Manager'
                if user == username and pwd == password:
                    print('登录成功')
                    return username, ident
    
    
    def main():
        usr, id = login()
        print('user,id :', usr, id)
        file = sys.modules['__main__']  # 获取到该文件的内存对象
        cls = getattr(file, id)  # Manager = getattr(当前文件,'Manager')
        # cls ==< class '__main__.Manager'>
        obj = cls(usr)  # 实例化类
        operate_dic = cls.OPERATE_DIC  # 调用类下的静态属性
        while True:
            for num, i in enumerate(operate_dic, 1):
                print(num, i[0])
            choice = int(input('num >>>'))
            choice_item = operate_dic[choice - 1]
            getattr(obj, choice_item[1])()  # 执行类下的方法
    
    
    main()

     当输入 zou 和123456 时

    请输入user : zou
    请输入pwd : 123456
    登录成功
    user,id : zou Manager
    1 创造学生账号
    2 创建课程
    3 查看学生信息
    num >>>2
    创建课程
    1 创造学生账号
    2 创建课程
    3 查看学生信息
    num >>>3
    查看学生信息
    1 创造学生账号
    2 创建课程
    3 查看学生信息
    num >>>

    当输入 test 666时

    请输入user : test
    请输入pwd : 666
    登录成功
    user,id : test Student
    1 查看所有课程
    2 选择课程
    3 查看已选择的课程
    num >>>1
    check_course
    1 查看所有课程
    2 选择课程
    3 查看已选择的课程
    num >>>2
    choose_course
    1 查看所有课程
    2 选择课程
    3 查看已选择的课程
    num >>>3
    查看已选择的课程
    1 查看所有课程
    2 选择课程
    3 查看已选择的课程
  • 相关阅读:
    c++命名规范与代码风格
    subline的多行游标快捷键
    selenium中的action
    Fiddler 教程(转)
    java.util.NoSuchElementException解决办法
    http协议中的URI
    深入研究java.lang.Runtime类(转)
    深入研究java.lang.Process类(转)
    java调用autoit3脚本
    AutoIT转
  • 原文地址:https://www.cnblogs.com/zouzou-busy/p/13236446.html
Copyright © 2020-2023  润新知