Python inherits magic methods based on __init__ value

Suppose I have a single class X. The goal Xis to wrap listor dictand provide listening opportunities. Everything works well.

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 ...

So, this can be used for wrapping dictas follows:

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

x.listen('foo', callback)

X['foo'] = True         # triggers event
X.update({
    'foo' : False       # triggers event
})

Or a list:

x = X([1,2])

x.listen(callback)

X.append(1)        # triggers event
X[0] = 10          # triggers event

Great. Almost to what I wanted to achieve ...

Now the current problem is that since it is Xintended for listand objects dict, it cannot inherit from either. This means that I do not have magic class functions, for example __contains__.

Which leads code like this

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

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

Throwing a KeyError.

, X. , , , self._obj list dict.

, , , , , dict list.

+4
3

-, 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__)

dict, dict:

>>> 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
+4

UserList UserDict collections

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)
-1

-

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

-2

Source: https://habr.com/ru/post/1686221/


All Articles