假设我有一个单类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
或{ {1}}。
答案 0 :(得分:6)
一种简单的方法是使用代理类,例如wrapt.ObjectProxy
。除了重写的方法之外,它的行为与“代理”类完全相同。但是,您只需使用self._obj
代替self.__wrapped__
即可访问“未代理”的对象。
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
答案 1 :(得分:-1)
您可以使用collections
中的UserList
或UserDict
from collections import UserList
class X(UserList):
def __init__(self, obj):
super().__init__()
self.data = obj
def __getattr__(self, name):
pass
# do stuff with self.data
def __getitem__(self, key):
return self.data[key]
def __setitem__(self, key, val):
self.data[key] = val
x0 = X([1, 2, 3])
x1 = X({1, 2, 3})
x2 = X({1: 1, 2: 2})
print(1 in x0)
print(1 in x1)
print(1 in x2)
答案 2 :(得分:-2)
尝试类似
的内容def contains (self, item):
If isinstance (self._obj, list):
return list.contains (self._obj, item)
If isinstance (self._obj, dict):
return dict.contains (self._obj, item)
或者你想继承什么方法。调用实例方法时,实例将自动与self一起传递。但是如果从类去除中调用方法,则需要传递一个对象,因为self需要一个值。
Class Test:
def print_cls (self):
print self.__class__.__name__
t = Test ()
t.print_cls () # self is teat
Test.print_cls (5)
# we replace self with another class object
# as long as the object you pass has the
# variables used in the method you call all should be good.
这将打印出Test
和int