我试图实现这一点: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
答案 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