python的反射

反射

在程序运行时候,动态的给一个对象添加属性。区别于编译时就已经确定好的状态,反射是在程序运行时动态的获取类型定义信息。在python中反射体现为我们可以使用一个字符串去获取这个对象的属性,或者给对象动态的添一个属性,这个字符串可能是临时生成的,没人知道他会是什么,只有程序运行时候才会进行添加。这和我们在编码状态下就写死的硬编码不同。

反射函数

python提供了一些反射的函数

getattr(object, name : str, default)     # 获取对象上名为name的属性,没有则为defalut
setattr(object, name : str, value)       # 运行时动态的给对象添加一个name名字的属性,或者方法
hasattr(object, name : str, default)     # 查询一个对象是否有这个字符串对应的属性

动态加载模块

import importlib

path = "lib.request.Request"  

module_name, class_name = path.rsplit(".", maxsplit=1)

# 通过字符串module_name,程序找到了该文件路径,并将这个静态文件加载到内存,创建了一个模块对象,该对象被赋值给module变量
module = importlib.import_module(module_name)             

# module是一个模块对象, 又通过class_name这个字符串,在其module模块中寻找该同名变量
plugin_module = getattr(module, class_name, EmptyPlug)    # 获取到插件模块
plugin = plugin_module()            # 实例化

如果在"lib.request.Request"路径下确实存在该模块和该类,那么这个模块和这个类都将被加载为一个内存的对象,并复制给对应的变量,哪个这个变量将能调用对应的属性和方法执行。这就实现了对模块的动态加载。

反射相关魔术方法

  __getattr__

  __setattr__

  __delattr__

  __getattribute__

# 调用ins.x时,在实例的mro中没有找到,即将引发AttributeError调用该函数item为"x"
def __getattr__(self, item)    # item 为self.访问的属性的字符串
    return
# getattr(class,key)函数会触发对象的 __getattribute__方法,如果方法没有找到,转而调用
# __getattr__,仍未找到使用默认值。
# ins.x 获取属性值时候调用,使用成员访问符访问这个实例的属性时候就会调用这个函数
# 除了 ins.x = value 是直接访问 __setattr__()
def __getattribute__(self, item): # 任何访问 self.属性的方法都将调用该属性,被调用的属性名,即为item的值 return value
# 调用 ins.x = value 时执行,重写该方法后,所有的self.key = value 都会调用该函数 def setattr(self, key, value): # key和value分别为"x" 和 value

# 执行del ins.x 时执行该函数 def delattr(self, key) # key 为 字符串"x"

这些方法将一个函数对属性的操作,映射到了一个函数上,并将访问的属性名的字符串,作为了函数的参数,这是一种对象和字符串之间的映射关系,也是通过反射实现。实际上python的对象大量的使用反射机制,可以查看对象的__dict__方法,对象将所有的属性都通过字符串的形式保存在该字典中,我们可以通过访问字典的方式去访问对象的上的属性。

原文地址:https://www.cnblogs.com/k5210202/p/13069992.html