簡體   English   中英

Python基於__init__值繼承魔術方法

[英]Python inherit magic methods based off __init__ value

讓我們想象一下,我有一個單一的 X級。 X的目的是包裝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來編寫兩個返回值。

我認為我最初可以用元類做這個,但這似乎不是一個解決方案,因為我需要訪問傳遞的值來檢查它是否是一個dictlist

一種簡單的方法是使用代理類,例如wrapt.ObjectProxy 除了重寫的方法之外,它的行為與“代理”類完全相同。 但是,您可以簡單地使用self.__wrapped__來訪問“unproxied”對象,而不是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

您可以使用集合中的 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)

嘗試類似的東西

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM