You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python动态包装器实现需求:基于对象数据暴露API调用

实现动态包装器类,自动暴露被包装对象的API

你现在的静态Wrapper类确实能处理Concrete对象,但局限性很明显:每新增一种要包装的类,就得手动给Wrapper加对应的转发方法,扩展性太差。要实现动态适配任意对象的包装器,Python的__getattr__魔法方法就是完美的解决方案。

先补全你原来的静态实现示例,方便对比:

class Concrete:
    def __init__(self, data):
        self.data = data
    def print_data(self):
        print(self.data)

class Wrapper:
    ''' 未来将支持包装多种对象,目前仅能处理Concrete对象。 '''
    def wrap_it(self, concrete):
        self.cco = concrete # concreteobject=cco
    def print_data(self):
        self.cco.print_data()

# 静态实现的使用
cco = Concrete(5)
wc = Wrapper()
wc.wrap_it(cco)
wc.print_data()  # 输出: 5

这个实现的问题在于:如果Concrete新增方法,或者你要包装另一个完全不同的类,必须修改Wrapper类手动添加转发逻辑,效率极低。

动态包装器的实现方案

下面是可以自动适配任意被包装对象的动态Wrapper类,核心就是利用__getattr__自动转发属性和方法调用:

class Concrete:
    def __init__(self, data):
        self.data = data
    def print_data(self):
        print(self.data)
    def double_data(self):
        self.data *= 2
        return self.data

class DynamicWrapper:
    ''' 支持动态包装任意对象,自动暴露被包装对象的所有API '''
    def __init__(self, wrapped_obj=None):
        self._wrapped = wrapped_obj  # 下划线标记为内部私有属性
    
    def wrap_it(self, wrapped_obj):
        self._wrapped = wrapped_obj
    
    def __getattr__(self, attr_name):
        # 当访问Wrapper没有的属性/方法时,转发给被包装对象
        if not self._wrapped:
            raise ValueError("还没有包装任何对象!请先调用wrap_it()传入目标对象。")
        
        if hasattr(self._wrapped, attr_name):
            return getattr(self._wrapped, attr_name)
        
        # 如果被包装对象也没有这个属性,抛出标准的AttributeError
        raise AttributeError(f"'DynamicWrapper' 对象没有属性 '{attr_name}'")

# 测试动态包装器
if __name__ == "__main__":
    # 包装Concrete对象
    cco = Concrete(5)
    wrapper = DynamicWrapper()
    wrapper.wrap_it(cco)
    
    # 直接调用被包装对象的方法和属性
    wrapper.print_data()  # 输出: 5
    print(wrapper.double_data())  # 输出: 10
    print(wrapper.data)  # 输出: 10
    
    # 切换包装另一个完全不同的类
    class GreetingService:
        def say_hello(self, name):
            return f"Hey, {name}!"
        def version(self):
            return "v1.0"
    
    greet_obj = GreetingService()
    wrapper.wrap_it(greet_obj)
    print(wrapper.say_hello("Ray"))  # 输出: Hey, Ray!
    print(wrapper.version())  # 输出: v1.0

方案核心原理

  • __getattr__是Python的魔法方法,只有当访问的属性/方法在当前对象中不存在时才会触发。我们在这里把请求转发给被包装的_wrapped对象,让Wrapper变成一个“透明代理”。
  • 这个实现完全不需要提前知道被包装对象的API结构,不管是Concrete还是其他任意类,只要是合法的Python对象,Wrapper都能自动适配。
  • 保留wrap_it方法,支持后续随时切换被包装的对象,灵活性拉满。

可选优化:初始化直接传入对象

如果你不想每次单独调用wrap_it,可以让__init__直接接受被包装对象,使用起来更便捷:

class DynamicWrapper:
    def __init__(self, wrapped_obj=None):
        self._wrapped = wrapped_obj
    
    def wrap_it(self, wrapped_obj):
        self._wrapped = wrapped_obj
    
    def __getattr__(self, attr_name):
        if not self._wrapped:
            raise ValueError("还没有包装任何对象!请先调用wrap_it()传入目标对象。")
        
        if hasattr(self._wrapped, attr_name):
            return getattr(self._wrapped, attr_name)
        
        raise AttributeError(f"'DynamicWrapper' 对象没有属性 '{attr_name}'")

# 直接在初始化时传入对象
wrapper = DynamicWrapper(Concrete(7))
wrapper.print_data()  # 输出:7

这样你的动态包装器就完全满足需求了,不管后续要包装什么类型的对象,都不需要修改Wrapper的代码,直接使用即可。

内容的提问来源于stack exchange,提问作者Ray Salemi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:42:53