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))) # True1.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)) # True2. 属性操作
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) # AttributeError2.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()) # 小红, 年级: 34. 方法操作
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)) # False4.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)) # 205. 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()
- 属性操作:
hasattr、getattr、setattr、delattr - 动态创建:使用
type()动态创建类 - inspect 模块:获取详细的代码结构信息
- 应用场景:序列化、依赖注入、插件系统、ORM
练习
- 编写一个函数,自动将对象的所有属性和值打印成表格
- 实现一个简易的 ORM,使用反射自动映射类属性到数据库字段
- 创建一个类装饰器,自动为类添加
to_dict()方法 - 使用 inspect 模块实现一个函数,打印另一个函数的参数列表和文档