Python的反射和自省

Python 的反射(Reflection)与自省(Introspection) —— 这两个概念在 Python 里非常重要,尤其在框架设计、动态加载模块、ORM(如 Django)、单元测试等场景中经常用到。



🧠 一、基本概念

✅ 自省(Introspection)

自省是指程序在运行时能够获取自身的信息,比如:
  • 一个对象属于哪个类;
  • 对象有哪些属性或方法;
  • 模块里定义了哪些变量、函数、类;
  • 函数的参数有哪些。

👉 简单来说,自省是“让程序认识自己”。



✅ 反射(Reflection)

反射是指在运行时动态地操作对象——比如根据字符串名去访问、修改或调用对象的属性和方法。

换句话说,自省是“了解自己”,而反射是“根据这种了解去做事情”。



🧩 二、常用自省与反射函数

函数作用
type(obj)查看对象的类型
id(obj)查看对象的内存地址
dir(obj)列出对象的所有属性和方法(包括内置的)
hasattr(obj, name)判断对象是否有某个属性或方法
getattr(obj, name, default)获取属性或方法(可提供默认值)
setattr(obj, name, value)动态设置属性
delattr(obj, name)动态删除属性
isinstance(obj, cls)判断对象是否某个类的实例
issubclass(sub, super)判断一个类是否另一个类的子类
callable(obj)判断对象是否可调用
inspect 模块提供更详细的自省功能(查看源代码、参数等)


🔍 三、反射示例

class Student:
    def __init__(self, name):
        self.name = name
    
    def say_hello(self):
        print(f"Hi, I'm {self.name}")

stu = Student("Alice")

# ---- 自省 ----
print(type(stu))        # <class '__main__.Student'>
print(dir(stu))         # 查看 stu 拥有哪些属性与方法
print(hasattr(stu, 'name'))  # True

# ---- 反射 ----
attr = getattr(stu, 'name')       # 动态获取属性值
print(attr)                       # Alice

method = getattr(stu, 'say_hello')  # 动态获取方法
method()                            # 调用方法:Hi, I'm Alice

setattr(stu, 'age', 20)           # 动态添加属性
print(stu.age)                    # 20

delattr(stu, 'age')               # 动态删除属性

💡 典型应用场景:

  • 动态加载模块或类(如 importlib.import_module())
  • 根据配置文件调用不同函数
  • Django ORM 根据模型类反射数据库字段


🔧 四、inspect 模块:更强的自省工具

Python 的标准库 inspect 提供了更强的自省功能。

import inspect

def demo_func(a, b, c=1):
    return a + b + c

print(inspect.signature(demo_func))     # (a, b, c=1)
print(inspect.getsource(demo_func))     # 查看源码
print(inspect.getmodule(demo_func))     # 获取函数所在模块
print(inspect.isfunction(demo_func))    # True
print(inspect.getmembers(demo_func))    # 获取所有成员信息


🧩 五、自省 vs 反射 对比总结

对比项自省 (Introspection)反射 (Reflection)
含义了解对象信息动态操作对象
典型函数type(), dir(), isinstance()getattr(), setattr(), delattr()
作用“知道有什么”“用这些做事情”
应用场景调试、分析程序结构框架设计、动态调用


🧱 六、实际应用例子(模拟路由调用)

比如在一个 Web 框架中,可以用反射根据 URL 动态调用控制器方法:

class UserView:
    def login(self):
        print("User login")
    
    def logout(self):
        print("User logout")

def run_action(view_class, action_name):
    view = view_class()
    if hasattr(view, action_name):
        func = getattr(view, action_name)
        func()  # 动态执行方法
    else:
        print("Action not found")

run_action(UserView, "login")   # 输出:User login
run_action(UserView, "logout")  # 输出:User logout


✅ 总结一句话:

自省是了解自己,反射是根据了解去动态操作。 Python 通过这些机制让代码更加“动态”和“灵活”,是其元编程能力的重要体现
文章标签:

评论(0)