Python基于__init__值继承魔术方法

X33*_*X33 4 python python-2.7

让我们想象一下我有一个单独的类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 ...
Run Code Online (Sandbox Code Playgroud)

所以这可以用来包装dict如此:

x = X({
    'foo' : False
})

x.listen('foo', callback)

X['foo'] = True         # triggers event
X.update({
    'foo' : False       # triggers event
})
Run Code Online (Sandbox Code Playgroud)

或者list:

x = X([1,2])

x.listen(callback)

X.append(1)        # triggers event
X[0] = 10          # triggers event
Run Code Online (Sandbox Code Playgroud)

大.几乎是我想要完成的......

现在目前的问题是,因为X是两个list和dict对象,它不能从任何继承.这意味着我没有魔术类的功能,比如__contains__.

这导致这样的代码

d = X({
        'foo' : True    
    })

    if 'foo' in d:
        print 'yahoo!'
Run Code Online (Sandbox Code Playgroud)

投掷一个KeyError.

如何在不定义我需要的每一种神奇方法的情况下解决这个问题X.如果我这样做了,为每个定义的,我将不得不编写基于断是否两个返回值self._obj是一个list或dict.

我认为我最初可以用元类来做这个,但这似乎不是一个解决方案,因为我需要访问传递的值来检查它是否是a dict或list.

MSe*_*ert 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__)
Run Code Online (Sandbox Code Playgroud)

如果你包装一个字典,这就像一个字典:

>>> d = Wrapper({'foo': 10})
>>> d['foo']
getitem
10
>>> 'foo' in d   # "inherits" __contains__
True
Run Code Online (Sandbox Code Playgroud)

并且像列表一样,如果列表被包装:

>>> d = Wrapper([1,2,3])
>>> d[0]
getitem
1
>>> for i in d:   # "inherits" __iter__
...     print(i)
1
2
3
Run Code Online (Sandbox Code Playgroud)

  • 所有`wrapt.ObjectProxy`都提供了所有特殊的方法和属性(后者称为`属性`对象),只是将它们代理到包装对象.所以`def __contains __(self,value):return self .__ wrapped __.__ contains __(value)`. (4认同)