假设我有一个单个类X
. X
的目的|是包裹一个list
或 dict
并提供事件监听功能。一切正常。
class X(object):
def __init__(self, obj)
self._obj = obj
def __getattr__(self, name):
# do stuff with self._obj
def __getitem__(self, key):
return self._obj[key]
def __setitem__(self, key, val):
self._obj[key] = val
# rest of functionality ...
所以这可以用来包装 dict
像这样:
x = X({
'foo' : False
})
x.listen('foo', callback)
X['foo'] = True # triggers event
X.update({
'foo' : False # triggers event
})
或者一个list
:
x = X([1,2])
x.listen(callback)
X.append(1) # triggers event
X[0] = 10 # triggers event
太棒了。几乎是我想要完成的...
现在的问题是,因为 X
两者都是list
和 dict
对象,它不能从任何一个继承。这意味着我没有魔法类函数,例如 __contains__
.
导致这样的代码
d = X({
'foo' : True
})
if 'foo' in d:
print 'yahoo!'
抛出 KeyError
.
如果不在 X
中定义我需要的所有魔法方法,我该如何解决这个问题? .如果我这样做,对于这些定义中的每一个,我都必须根据是否 self._obj
编写两个返回值。是 list
或 dict
.
一开始我想我可以用元类来做这件事,但这似乎不是一个解决方案,因为我需要访问传递的值来检查它是否是 dict
或 list
.
最佳答案
一种简单的方法是使用代理类,例如 wrapt.ObjectProxy
.除了覆盖的方法外,它的行为与“代理”类完全一样。但是,您可以简单地使用 self.__wrapped__
来访问“未代理”对象,而不是 self._obj
。
from wrapt import ObjectProxy
class Wrapper(ObjectProxy):
def __getattr__(self, name):
print('getattr')
return getattr(self.__wrapped__, name)
def __getitem__(self, key):
print('getitem')
return self.__wrapped__[key]
def __setitem__(self, key, val):
print('setitem')
self.__wrapped__[key] = val
def __repr__(self):
return repr(self.__wrapped__)
如果你包装一个字典,这就像一个字典:
>>> d = Wrapper({'foo': 10})
>>> d['foo']
getitem
10
>>> 'foo' in d # "inherits" __contains__
True
和列表一样,如果列表被包装:
>>> d = Wrapper([1,2,3])
>>> d[0]
getitem
1
>>> for i in d: # "inherits" __iter__
... print(i)
1
2
3
关于Python 继承基于 __init__ 值的魔术方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46367953/