代码改变世界

Python 反射

2018-06-26 08:48  钱先生  阅读(216)  评论(0编辑  收藏  举报

反射

  • 通过字符串映射或修改程序运行时的状态,属性,方法.
  • 有以下四种方法:
    • getattr(object, name, default = None)
    • hasattr(object, name)
    • setattr(x,y,v)
    • delattr(x,y)
    • #!/usr/bin/python
      # -*- coding: utf-8 -*-
      
      
      def bulk(self):
          print("%s is yelling...." % self.name)
      
      
      class Dog(object):
          def __init__(self, name):
              self.name = name
      
          def eat(self, food):
              print("%s is eating %s...", self.name, food)
      
          def walk(self):
              print("%s is walking...", self.name)
      
      
      d = Dog("NHY")
      choice = input(">>:").strip()   # 用户输入"吃", 就调用eat()方法; 用户输入"走", 就调用walk()方法
      
      # print(hasattr(d, choice))  # 判断用户输入是否存在于实例d中. 若用户输入eat, 会返回True;  若用户输入talk,会返回False.
      
      """
      但是即使eat返回True,也不能直接调用 d.choice, 因为choice是不存在的, 必须把用户输入的eat调出来, 需要用到getattr()方法
      """
      # print(getattr(d, choice))  # 若用户输入eat, 就返回一个内存地址(返回内存地址之后, 加括号就能调用相应方法了); 若用户输入talk,因为不存在, 会返回False.
      
      # getattr(d, choice)("包子")  # 若用户输入eat,此行代码相当于调用 eat()方法. 若不需要传参数, 直接getattr(d, choice)()即可.
      
      """
      反射步骤总结: 
        1. hasattr(obj, name_str) 判断是否存在某字符串的方法映射
        2. getattr(obj, name_str) 若该映射存在, 获取该映射对应方法的内存地址
        3a. getattr(obj, name_str)() 如果是一个方法, 获取内存地址之后, 调用相关方法
        3b. setattr(ojb, 'y', v) 如果是一个属性, 重新设置该属性的值. is equivalent to obj.y = v.
        4. delattr() 删除一个属性
      """
      
      # 传递一个动态方法
      if hasattr(d, choice):
          # getattr(d, choice)()  # 这样直接调用eat()方法, 有时还需要传参数,可以用下面的方法
          func = getattr(d, choice)
          func("馒头")
      else:
          setattr(d, choice, bulk)  # 传递一个动态方法. 即不存在的映射, 可以添加. 但是前提相关方法必须已经存在.
          setattr(d, choice, None)  # 传递一个动态属性
      
      d.talk(d)  # 用户输入talk, 所以要调用talk(),而不是bulk(). bulk相当于一个变量名, 此处因用户输入了talk,用talk来代替. 相当于d.talk = bulk, 所以d.talk()就是调用bulk()方法.
      
      """
      上面写死了. 因为不确定用户choice会输入什么, 所以应该用一个变量来接收getattr()的值
      """
      if hasattr(d, choice):
          # getattr(d, choice)()  # 这样直接调用eat()方法, 有时还需要传参数,可以用下面的方法
          func = getattr(d, choice)
          func("馒头")
      else:
          setattr(d, choice, bulk)  # 传递一个动态方法. 即不存在的映射, 可以添加. 但是前提相关方法必须已经存在.
          setattr(d, choice, None)  # 传递一个动态属性
          func = getattr(d, choice)
          func(d)  # 这样不论用户choice输入的是什么都可以直接调用func(d)来执行了.不用写死成d.talk().
      
      
      
      # 传递一个动态属性, 或给已有属性重新赋值
      if hasattr(d, choice):
          attr = getattr(d, choice)
          setattr(d, choice, "RGH")  # 更改已有属性值. 在choice里填name, 改的就是name的值.
      else:
           setattr(d, choice, None)  # 传递一个动态属性. None是这个动态属性的默认值.可以是None,也可以是其它值,如2233等.
           # setattr(d, choice, 22)
           print(getattr(d, choice))
      
      print(d.name)
      
      
      # 删除一个属性
      if hasattr(d, choice):
          delattr(d, choice)