Python对象包装器

5

我正在尝试创建一个包装类,其行为几乎与被包装的对象相同。到目前为止,我已经想出了以下代码:

import functools
import types

method_wrapper = type((None).__str__)

class Box:

    def __new__(cls, obj):
        attrs = {}
        attr_names = dir(obj)

        for attr_name in attr_names:
            attr = obj.__getattribute__(attr_name)

            if isinstance(attr, (types.MethodType, method_wrapper)):
                "Attr is a bound method, ignore self"
                @functools.wraps(attr)
                def wrapped_attr(self, *args, **kwargs):
                    return attr(*args, **kwargs)
                attrs[attr_name] = wrapped_attr

            elif isinstance(attr, types.FunctionType):
                "attr is a static method"
                attrs[attr_name] = staticmethod(attr)

            else:
                "attr is a property"
                attrs[attr_name] = attr

        cls = type(type(obj).__name__,
                   (cls, type(obj)),
                   attrs)

        return object.__new__(cls)

我尝试使用以下内容进行测试:

if __name__ == '__main__':
    x=Box(object())

然而,它会出现以下错误信息:
TypeError: __init__() should return None, not 'NotImplementedType'

__init__ 被正确地调用,使用了 isinstance(attr, (types.MethodType, method_wrapper)),并且似乎执行了 wrapped_attr。你有任何想法为什么会发生这种情况吗?


1
出于好奇,你想通过这段代码实现什么目标? - user1971598
我找到了这个解决方案,以实现编写代理类的更大目标,但是我仍然想知道为什么__init__返回NotImplemented。 - Joshua
2
@EdgarAroutiounian 我正在尝试为我编写的LISP解释器添加调试信息。使用包含调试信息的代理对象将允许我保留我的求值器和解析器的结构,同时更改分词器和错误处理程序。 - Joshua
1个回答

1
问题在这里:

for ...:
    attr = ...
    ...
    def wrapped_attr(...):
        ..attr..

这个不像预期的那样工作,因为 attrfor 循环中被重新绑定到各种值。所有子函数将看到最后一个绑定的值,而不是它在循环迭代中所具有的值。在这种情况下,按字母顺序排列的最后一个绑定值是 __subclasshook__,通常在使用随机参数调用时返回 NotImplemented。

谢谢!生成闭包并传入attr似乎是最好的解决方法,例如def closure(attr):def wrapped_attr(...):...?但这种方法看起来有点凌乱。 - Joshua
@Joshua:是的。这要怪Python的作用域规则,它们通常很好,但有些意外的效果,比如这个。 - Armin Rigo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接