目录

Python 反射与内省

学习目标

  • 理解反射和内省的概念
  • 掌握常用内置函数:type()isinstance()hasattr()
  • 学会动态创建类和修改对象
  • 理解 inspect 模块的使用

1. 类型检查

1.1 type() 和 isinstance()

# type() - 获取对象类型
print(type(42))           # <class 'int'>
print(type("hello"))      # <class 'str'>
print(type([1, 2, 3]))    # <class 'list'>

# isinstance() - 检查类型(推荐)
print(isinstance(42, int))           # True
print(isinstance("hello", str))      # True
print(isinstance([1, 2], list))      # True
print(isinstance([1, 2], tuple))     # False

# 检查多个类型
print(isinstance(42, (int, float)))  # True
print(isinstance(3.14, (int, float))) # True

1.2 为什么优先使用 isinstance()

class Animal:
    pass

class Dog(Animal):
    pass

dog = Dog()

# type 不考虑继承
print(type(dog) == Animal)   # False

# isinstance 考虑继承
print(isinstance(dog, Animal))  # True
print(isinstance(dog, Dog))     # True

2. 属性操作

2.1 hasattr、getattr、setattr、delattr

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def greet(self):
        return f"你好, 我是 {self.name}"

p = Person("小明", 25)

# hasattr - 检查是否有属性
print(hasattr(p, 'name'))      # True
print(hasattr(p, 'gender'))    # False
print(hasattr(p, 'greet'))     # True(方法也是属性)

# getattr - 获取属性
print(getattr(p, 'name'))      # 小明
print(getattr(p, 'age'))       # 25
print(getattr(p, 'gender', '未知'))  # 未知(提供默认值)

# setattr - 设置属性
setattr(p, 'gender', '男')
print(p.gender)                # 男

# delattr - 删除属性
delattr(p, 'gender')
# print(p.gender)  # AttributeError

2.2 动态属性操作示例

def serialize(obj):
    """将对象序列化为字典"""
    result = {}
    for attr in dir(obj):
        if not attr.startswith('_'):  # 忽略私有属性
            value = getattr(obj, attr)
            if not callable(value):   # 忽略方法
                result[attr] = value
    return result

class User:
    def __init__(self, username, email):
        self.username = username
        self.email = email
        self._password = "secret"  # 私有属性
    
    def login(self):
        pass

user = User("alice", "alice@example.com")
print(serialize(user))
# {'email': 'alice@example.com', 'username': 'alice'}

3. 动态创建对象

3.1 使用类对象创建实例

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __repr__(self):
        return f"Point({self.x}, {self.y})"

# 正常创建
p1 = Point(1, 2)

# 使用类对象动态创建
cls = Point
p2 = cls(3, 4)
print(p2)  # Point(3, 4)

3.2 使用 type() 动态创建类

# type(name, bases, dict)
# name: 类名
# bases: 父类元组
# dict: 属性和方法字典

# 动态创建类
Person = type('Person', (), {
    '__init__': lambda self, name: setattr(self, 'name', name),
    'greet': lambda self: f"你好, {self.name}"
})

p = Person("小明")
print(p.greet())  # 你好, 小明

# 带继承的动态类
Student = type('Student', (Person,), {
    '__init__': lambda self, name, grade: (
        Person.__init__(self, name),
        setattr(self, 'grade', grade)
    ),
    'info': lambda self: f"{self.name}, 年级: {self.grade}"
})

s = Student("小红", 3)
print(s.greet())  # 你好, 小红
print(s.info())   # 小红, 年级: 3

4. 方法操作

4.1 获取方法信息

class Calculator:
    def add(self, a, b):
        """加法运算"""
        return a + b
    
    def multiply(self, a, b=1):
        """乘法运算"""
        return a * b

calc = Calculator()

# 获取方法
method = getattr(calc, 'add')
print(method(2, 3))  # 5

# 检查是否是方法
print(callable(calc.add))       # True
print(callable(calc.multiply))  # True
print(callable(42))             # False

4.2 动态调用方法

def call_method(obj, method_name, *args, **kwargs):
    """动态调用对象方法"""
    if hasattr(obj, method_name):
        method = getattr(obj, method_name)
        if callable(method):
            return method(*args, **kwargs)
    raise AttributeError(f"对象没有方法: {method_name}")

# 使用
calc = Calculator()
print(call_method(calc, 'add', 5, 3))       # 8
print(call_method(calc, 'multiply', 4, 5))  # 20

5. inspect 模块

5.1 检查模块和类

import inspect

class Example:
    """示例类"""
    class_var = "类变量"
    
    def __init__(self):
        self.instance_var = "实例变量"
    
    def method(self):
        """示例方法"""
        pass

# 获取类成员
print("类成员:")
for name, member in inspect.getmembers(Example):
    if not name.startswith('_'):
        print(f"  {name}: {type(member).__name__}")

# 获取方法
print("\n方法:")
for name, method in inspect.getmembers(Example, inspect.isfunction):
    print(f"  {name}")

5.2 检查函数签名

def example_function(a, b=10, *args, c=20, **kwargs):
    """示例函数"""
    pass

# 获取签名
sig = inspect.signature(example_function)
print(f"函数签名: {sig}")

# 获取参数
for name, param in sig.parameters.items():
    print(f"参数: {name}")
    print(f"  类型: {param.kind.name}")
    print(f"  默认值: {param.default}")
    print()

5.3 获取源代码

# 获取函数的文档字符串
print(inspect.getdoc(example_function))

# 获取源代码(如果可用)
try:
    print(inspect.getsource(example_function))
except TypeError:
    print("无法获取源代码")

6. 类内省

6.1 获取类的层次结构

class Animal:
    pass

class Mammal(Animal):
    pass

class Dog(Mammal):
    pass

# 获取类的 MRO(方法解析顺序)
print(Dog.__mro__)
# (<class '__main__.Dog'>, <class '__main__.Mammal'>, 
#  <class '__main__.Animal'>, <class 'object'>)

# 获取所有父类
print(Dog.__bases__)  # (<class '__main__.Mammal'>,)

# 获取子类
print(Animal.__subclasses__())  # [<class '__main__.Mammal'>]

6.2 获取类的属性

class MyClass:
    class_attr = "类属性"
    
    def __init__(self):
        self.instance_attr = "实例属性"
    
    @classmethod
    def class_method(cls):
        pass
    
    @staticmethod
    def static_method():
        pass

obj = MyClass()

# 实例属性
print("实例属性:", obj.__dict__)  # {'instance_attr': '实例属性'}

# 类属性
print("类属性:", MyClass.__dict__.keys())

# 获取所有属性(包括继承的)
print("所有属性:", dir(obj))

7. 实际应用

7.1 简单的依赖注入

class Container:
    """简单依赖注入容器"""
    
    def __init__(self):
        self._services = {}
    
    def register(self, name, instance):
        self._services[name] = instance
    
    def resolve(self, cls):
        """解析类的依赖并创建实例"""
        sig = inspect.signature(cls.__init__)
        params = list(sig.parameters.items())[1:]  # 排除 self
        
        kwargs = {}
        for name, param in params:
            if name in self._services:
                kwargs[name] = self._services[name]
            elif param.default != inspect.Parameter.empty:
                kwargs[name] = param.default
            else:
                raise ValueError(f"无法解析依赖: {name}")
        
        return cls(**kwargs)

class Database:
    def query(self):
        return "查询结果"

class UserService:
    def __init__(self, db):
        self.db = db
    
    def get_users(self):
        return self.db.query()

# 使用
container = Container()
container.register('db', Database())

service = container.resolve(UserService)
print(service.get_users())  # 查询结果

7.2 自动注册装饰器

class PluginRegistry:
    """插件注册表"""
    plugins = {}
    
    @classmethod
    def register(cls, name):
        def decorator(plugin_class):
            cls.plugins[name] = plugin_class
            return plugin_class
        return decorator

@PluginRegistry.register("email")
class EmailPlugin:
    def send(self):
        return "发送邮件"

@PluginRegistry.register("sms")
class SMSPlugin:
    def send(self):
        return "发送短信"

# 动态创建插件
plugin_name = "email"
if plugin_name in PluginRegistry.plugins:
    plugin = PluginRegistry.plugins[plugin_name]()
    print(plugin.send())  # 发送邮件

本节小结

  • 内省:程序检查自身结构和类型的能力
  • type() / isinstance():类型检查,优先使用 isinstance()
  • 属性操作hasattrgetattrsetattrdelattr
  • 动态创建:使用 type() 动态创建类
  • inspect 模块:获取详细的代码结构信息
  • 应用场景:序列化、依赖注入、插件系统、ORM

练习

  1. 编写一个函数,自动将对象的所有属性和值打印成表格
  2. 实现一个简易的 ORM,使用反射自动映射类属性到数据库字段
  3. 创建一个类装饰器,自动为类添加 to_dict() 方法
  4. 使用 inspect 模块实现一个函数,打印另一个函数的参数列表和文档