Python - 伪造类型续

时间:2015-07-27 16:14:33

标签: python python-3.x

我试图实现这一点:How to fake type with Python。我包装了一些我无法控制的.NET对象,所以不要通过包装器中类的实例化来调用它们__new__。我从上面的问题中获取了代码并构建了一个简单的示例:

class WrappableInt(object):
    def __new__(cls,*args,**kwargs):
        print("Making a new wrapint")
        return super().__new__(cls)
    def __init__(self,x):
        self.x=x


def wrap_user(wrapee):
    class wrapped_user(type(wrapee)):
        def __new__(cls,*args,**kwargs):
            return object.__new__(cls)
        def __init__(self):
            pass
        def gimmieFive(self):
            return 5
        def __getattribute__(self, attr):
            self_dict = object.__getattribute__(type(self), '__dict__')
            if attr in self_dict:
                return self_dict[attr]
            return getattr(wrapee, attr)
    return wrapped_user()

当我运行以下测试时,一切都按预期进行:

>>> z=WrappableInt(3)
Making a new wrapint
>>> p=wrap_user(z)
>>> print(p.x)
3

然而,当我运行gimmieFive时,我得到以下内容:

>>> p.gimmieFive()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: gimmieFive() missing 1 required positional argument: 'self'

为什么python认为gimmieFive是一个静态方法,当它似乎知道__getattribute__不是?它会愉快地运行,例如:

>>> p.gimmieFive(1)
5

1 个答案:

答案 0 :(得分:1)

你在这里绕过正常的descriptor protocol__getattribute__不只是在类上查找名称,如果检索到的对象支持绑定,它还绑定它们。

Python函数对象是描述符,将它们绑定到实例会生成一个方法对象,该方法在调用时作为第一个函数参数传入绑定实例。您将返回原始未绑定的函数对象。

重新实现绑定行为是复杂的。如果实例属性与从类中检索的描述符对象发生冲突,则需要检查本地属性,确定描述符是数据描述符还是regural描述符,并决定返回哪一个。 / p>

一个简单而基本的实现至少需要支持__get__绑定:

if attr in self_dict:
    obj = self_dict[attr]
    if hasattr(obj, '__get__'):
        obj = obj.__get__(self, type(self))
    return obj

这可能已经足够您的用例,因为您的wrapped_user课程目前没有任何数据描述符。

通过上述更改,您的具体示例按预期工作:

>>> z=WrappableInt(3)
Making a new wrapint
>>> p=wrap_user(z)
>>> print(p.x)
3
>>> p.gimmieFive()
5