我尝试实现类似dict
的对象,可以使用__getattr__
和__setattr__
进行访问/修改,以方便用户使用。该类还实现了一些其他简单的功能。
使用this answer作为模板,我的实现目前如下:
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)
答案 0 :(得分:2)
当我写这个问题并将其正式化时,我找到了答案(在我身上发生了很多)。也许这可以帮助别人。
我的解决方案如下:
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
属性并从基类调用以避免递归。很简单但很容易让我错过!
我添加了添加您不想保留在store
中的属性的功能(即属性的通常含义)。我还将store
实现为OrderedDict
,但这仅适用于我的用例。显然set_inst_attr
例外是暂时的/占位符。
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)