用于将其他类的项作为属性访问的代理类(\u getitem_uuinfinite recursion)

2024-06-01 10:53:14 发布

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

我有一个类LabelMapper(一个boost::python类),它实现字典协议。我想有一个代理类,它将使用属性来访问该目录。我看过很多关于重写__setitem____getitem__的帖子,但我似乎不能正确理解。在

由于self.mapper调用了LabelMapperProxy.__getattr__,这又需要self.mapper等等,所以这种天真的方法(如下)导致了无限递归。在

class LabelMapper(object):
   def __init__(self): self.map={}
   def __getitem__(self,key): return self.map[key]
   def __setitem__(self,key,val): self.map[key]=val
   def __delitem__(self,key): del self.map[key]

class LabelMapperProxy(object):
   def __init__(self,mapper): self.mapper=mapper
   def __getattr__(self,key): return self.mapper[key]
   def __setattr__(self,key,val): self.mapper[key]=val
   def __delattr__(self,key): del self.mapper[key]

lm=LabelMapper()
lm['foo']=123

# construct the proxy
lmp=LabelMapperProxy(mapper=lm)
print lmp.foo                    # !!! recursion
lmp.bar=456
print lmp.bar,lm['bar']

解决办法是什么?也许在标准库中有这样的代理吗?在


Tags: keyselfmap代理defbarvallm
2条回答

这是个陷阱:

class LabelMapperProxy(object):
   def __init__(self, mapper):
       # This will not assign this object's attribute 
       # since __setattr__ is overriden.
       # Instead, it will do self.mapper['mapper'] = mapper
       self.mapper=mapper

   def __getattr__(self, key): 
       # And this won't find `self.mapper` and resort to __getattr__
       # (which is itself)
       return self.mapper[key]  

   def __setattr__(self, key, val): 
       self.mapper[key]=val

   def __delattr__(self, key): 
       del self.mapper[key]

您正在尝试在您的Proxy实例上设置一个新属性:

class LabelMapperProxy(object):
    def __init__(self, mapper): self.mapper = mapper

这将触发一个__setattr__,它试图访问不存在的self.mapper属性,因此会查询__getattr__(这是为所有丢失的属性调用的)。并且__getattr__试图访问self.mapper。。。。在

解决方案是直接在self.__dict__中设置mapper

^{pr2}$

或者,只对mapper属性使用原始基类__setattr__

class LabelMapperProxy(object):
   def __init__(self, mapper): self.mapper = mapper

   def __setattr__(self, key, val):
       if key == 'mapper':
           return super(LabelMapperProxy, self).__setattr__(key, val)
       self.mapper[key] = val

相关问题 更多 >