Python面向对象之反射
反射
【一】什么是反射
- 反射是一种程序可以访问、检测和修改其本身状态或行为的能力。
- 在 Python 中,反射主要指通过字符串的形式操作对象的属性。
【二】Python中的反射
- 通过字符串的形式操作对象相关的属性。
- python中的一切事物都是对象(都可以使用反射)
【三】反射方法
class A:
def __init__(self, name):
self.name = name
def run(self):
print(f"{self.name}在跑")
a= A('cat')
【1】getattr
getattr(object, name[, default])
- 获取对象的属性值,如果属性不存在,可提供默认值。
print(getattr(a, 'name')) # cat
print(getattr(a, 'age')) # AttributeError: 'A' object has no attribute 'age'
# 获取对象中的值,如果不存在则报错,但是可以指定不存在的时候返回的默认值
print(getattr(person,'sex',None))
# 如果获取的是对象中的函数,那会直接返回函数的内存地址,可以直接调用该函数
res = getattr(person,'run')
【2】hasattr
hasattr(object, name)
- 判断对象是否具有指定属性,如果存在就返回 True,不存在就返回 False
print(hasattr(a, 'name')) # True
print(hasattr(a, 'age')) # False
【3】setattr
setattr(object, name, value)
- 设置对象的属性值
print(hasattr(a, 'age')) # False
setattr(a, 'age', 18)
print(getattr(a, 'age')) # 18
def eat():
print(f'在吃饭')
a = A('cat')
setattr(a, 'eat', eat)
getattr(a, 'eat')
a.eat() # 在吃饭
【4】delattr
delattr(object, name)
class Person:
name='as'
def __init__(self, age):
self.age = age
def run(self):
print("跑步")
per = Person('tom')
- 如果是类,可以删除自己的数据属性和函数属性
delattr(Person, 'name')
delattr(Person, 'run')
print(hasattr(Person, 'name')) # False
print(hasattr(Person, 'run')) # False
-
如果是对象,只能删除自己的 数据属性
-
删除类中的数据属性,不能删除对象中的父类中的数据属性
delattr(per, 'name') # 报错
delattr(per, 'age')
delattr(per, 'run') # 报错
【四】类也是对象
- 只有类经过初始化以后。,才会将 init 中属性加载到对象中
- 类没有初始化的时候,是不会存在init里面的属性的
print(hasattr(A, 'name')) # False
print(hasattr(A, 'run')) # True
【五】反射当前模块中的成员
import sys
def d1():
...
module = sys.modules[__name__]
print(hasattr(module, 'sys')) # True
print(hasattr(module, 'd1')) # True
【六】反射的好处
【1】实现可插拔机制
-
反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,意味着可以在程序运行过程中动态地绑定接口的实现。
-
这种灵活性使得程序更容易扩展和维护
class Interface:
def run(self):
pass
class A(Interface):
def run(self):
print("插件A被启动")
class B(Interface):
def run(self):
print("插件B被启动")
def run_plugin(plugin):
plugin.run()
# 使用反射调用插件
plugin_name = input("请输入插件名字(A or B) :>>>> ")
# 从全局名称空间中获取到 插件名字对应的类
plugin_class = globals().get(plugin_name)
# 判断一下当前类是否存在 并且 判断当前类是否 有 PluginInterface 接口
if plugin_class and issubclass(plugin_class, Interface):
# 如果都成立会触发相应的方法
run_plugin(plugin_class())
else:
# 不存在则抛出异常
print("Invalid plugin name")
【2】动态导入模块(基于反射当前模块成员)
- 动态导入模块是指在程序运行时根据字符串的形式导入模块。
- 通过反射,可以动态导入模块的成员,实现更灵活的代码组织和管理。
module_name = input("请输入模块名 :>>>> ")
method_name = input("请输入方法名 :>>>> ")
try:
# 动态导入模块
module = importlib.import_module(module_name)
# 反射是否存在当前方法
method = getattr(module, method_name)
# 如果存在则执行当前方法
method()
except ImportError:
print(f"找不到模块 {module_name}")
except AttributeError:
print(f"模块 {module_name} 中不存在方法 {method_name}")