Python基于__init__值继承魔术方法

时间:2017-09-22 15:11:49

标签: python python-2.7

假设我有一个XX的目的是包装listdict并提供事件监听功能。一切顺利。

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适用于listdict个对象,所以它无法继承。这意味着我没有神奇的类功能,例如__contains__

这导致像这样的代码

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

    if 'foo' in d:
        print 'yahoo!'

投掷KeyError

如果不在X内定义我需要的每一种神奇方法,我该如何解决这个问题。如果我这样做,对于每个定义,我必须根据self._objlist还是dict写出两个返回值。

我认为我最初可以使用元类进行此操作,但这似乎不是一个解决方案,因为我需要访问传递的值以检查它是否为dict或{ {1}}。

3 个答案:

答案 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

中的UserListUserDict
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.

这将打印出Testint