使用__getattr__和__setattr__功能实现类似dict的对象 [英] Implementing a dict-like object with __getattr__ and __setattr__ functionality
问题描述
我正在尝试实现类似dict
的对象,该对象可以通过__getattr__
和__setattr__
进行访问/修改,以方便用户使用.该类还实现了其他一些简单的功能.
I'm trying to implement a dict
-like object which can be accessed/modified with __getattr__
and __setattr__
for ease of use for my users. The class also implements some other simple functionality.
使用此答案作为模板,我的实现当前如下:
Using this answer as a template, my implementation is currently as follows:
from collections import MutableMapping
class Dictish (MutableMapping):
"""
A dict-like mapping object. vals are always coerced to str.
Should provide __getattr__ and __setattr__ as aliases for
__getitem__ and __setitem__.
"""
def __init__ ( self, *args, **kwargs ):
self.store = dict()
self.update(dict(*args,**kwargs))
def __getitem__ ( self, key : str ) -> str:
return self.store[key]
def __setitem__ ( self, key : str, val : str ) -> None:
self.store[key] = str(val)
def __delitem__ ( self, key : str ) -> None:
del self.store[key]
def __iter__ ( self ):
return iter(self.store)
def __len__ ( self ) -> int:
return len(self.store)
def __repr__ ( self ) -> str:
return repr(self.store)
# works fine by itself, but goes into infinite recursion
# when __setattr__ is defined
def __getattr__ ( self, attr : str ) -> str:
return self.__getitem__(attr)
# def __setattr__ ( self, attr : str, val : str ) -> None:
# self.__setitem__(attr,val)
推荐答案
在编写问题并将其形式化时,我找到了答案(对我来说很常见).也许这可以帮助其他人.
As I was writing and formalizing the question, I found the answer (happens to me a lot). Maybe this can help someone else.
对我来说,解决方法如下:
The solution for me was the following:
def __getattr__ ( self, attr : str ) -> str:
return self.__getitem__(attr)
def __setattr__ ( self, attr : str, val : str ) -> None:
if attr == 'store':
super().__setattr__(attr,val)
else:
self.__setitem__(attr,val)
关键是必须将store
属性分离出来并从基类中调用,以避免递归.很简单,但我很容易错过!
The key is that the store
attribute must be separated out and called from the base class to avoid recursion. Pretty simple but was easy for me to miss!
我添加了一些功能,用于添加您不想保留在store
中的属性(即属性的通常含义).我也将store
实现为OrderedDict
,但这仅用于我的用例.显然,set_inst_attr
例外是临时的/占位符.
I added functionality for adding attributes that you do not want to keep in store
(ie. the usual meaning of attributes). I also implemented store
as an OrderedDict
, but this is just for my use-case. Obviously the set_inst_attr
exception is temporary/a placeholder.
from collections import MutableMapping, OrderedDict
class ODictish (MutableMapping):
"""
An OrderedDict-like mapping object.
Provides __getattr__ and __setattr__ as aliases for __getitem__
and __setitem__.
Attributes which you do not want to keep in 'store' can be set with
self.set_inst_attr.
"""
def __init__ ( self , od=None):
if od is None: od = OrderedDict()
super().__setattr__('store', OrderedDict(od))
def __getitem__ ( self, key ):
return self.store[key]
def __setitem__ ( self, key, val ):
self.store[key] = val
def __delitem__ ( self, key ):
del self.store[key]
def __iter__ ( self ):
return iter(self.store)
def __len__ ( self ):
return len(self.store)
def __repr__ ( self ):
return repr(self.store)
def __getattr__ ( self, attr ):
if attr in vars(self):
return vars(self)[attr]
return self.__getitem__(attr)
def __setattr__ ( self, attr, val ):
if attr in vars(self):
self.set_inst_attr(attr,val)
else:
self.__setitem__(attr,val)
def set_inst_attr ( self, attr, val ):
if attr == 'store':
raise Exception("Don't do that.")
super().__setattr__(attr,val)
def move_to_end ( self, key, last=True ):
self.store.move_to_end(key,last)
这篇关于使用__getattr__和__setattr__功能实现类似dict的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!