当包装器getattribute调用obj的getitem方法时,我们如何获得包装对象obj的属性?

2024-04-29 01:22:32 发布

您现在位置:Python中文网/ 问答频道 /正文

假设DotDict是一个包装类,它允许您访问包装对象的 __getitem__方法到__getattr__

假设obj不是DotDict的实例,如下所示 关于obj是真的:

obj.a  returns 'apple'
obj[a] returns 999

现在我们将对象包装在DotDict中:

wobj = DotDict(obj)

wobj.a现在返回与obj[a],999相同的值。
obj.a更难获得。你知道吗

class DotDict():

    def __init__(self, true_self):
        assert (not inspect.isclass(true_self))
        object.__setattr__(self, 'true_self', true_self)

    def __getattribute__(self, attr_name):
        return true_self[attr_name]

一种有缺陷的方法:

一种方法是允许用户在属性名的开头加下划线: 如果_a也是obj.__getitem__的有效键,请尝试:

x = wobj.__a
x = wobj.___a
x = wobj.____a
x = wobj._____a

。。。等等。你知道吗

  def __getattribute__(self, attr_name):
            true_self = object.__getattribute__(self, 'true_self')
            try:
                return true_self[attr_name]
            except KeyError:
                # there is a __getitem__ method,
                # but attr_name is not a valid key
                pass
            try:                
                attr_name = attr_name.lstrip('_')
                attr = getattr(true_self, attr_name)
                return attr
            except AttributeError:
                # if "a" is not an attribute of obj, then raise an exception
                raise AttributeError

尝试更多下划线不会导致无限循环。 如果___...___a不是有效键,则会引发异常 到obj.__getitem__,并且obj没有名为a的属性 只有名称不以下划线开头的obj属性可以通过wobj访问

这种方法的一个问题是,如果wobj.___a返回一些东西,我们如何知道我们是得到了obj[___a]还是obj.a? 如何区分__getattribute__返回的结果?你知道吗

下面是一个小演示脚本:

class DemoClass:
    def __init__(self):      
        self.a = 'attribute a, not getitem'
        self.c = list()
        s = 'a'
        for k in range(0, 10):
            s = '_' + s
            self.c.append(s)

def __getitem__(self, key):
    print('__getitem__ was called')
    if key in self.c:
        return '__getitem__' + key
    else:
        raise KeyError

obj = DemoClass()
ddobj = DotDict(obj)
attr_name = 'a'
try:
    count_underscores = 0
    while True:
        attr = getattr(ddobj, attr_name)
        print('potential attr == ', attr)
        attr_name = '_' + attr_name
        count_underscores += 1
except AttributeError:
    print('there is no attribute named ', attr_name.lstrip('_'))

print('count_underscores == ', count_underscores)
print('attr == ', attr)

Tags: 方法nameselftrueobjreturnisdef