python--反射

2021-03-04 07:29

阅读:692

标签:成员   ast   事件   命名空间   setattr   类方法   ror   use   --   

什么是反射

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

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
__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 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 ==
    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 查看已选择的课程

 

python--反射

标签:成员   ast   事件   命名空间   setattr   类方法   ror   use   --   

原文地址:https://www.cnblogs.com/zouzou-busy/p/13236446.html


评论


亲,登录后才可以留言!