这个类在键不存在时返回None
(而不是崩溃整个应用程序),并允许访问像属性这样的键:
class Dict(dict): # a dictionary that returns @None when a key doesn't exist (as opposed to crashing the entire application...) and allows accessing keys like attributes
def __init__( self, *args,**kwargs):
super(Dict,self).__init__(*args,**kwargs)
self.__dict__ = self # this allows accessing keys like attributes
def __getitem__(self, key,default=None):
return dict.get(self, key,default) # return None if the key exists not
def __getattribute__(self, attr): # return None if the attribute exists not
try: return object.__getattribute__(self,attr)
except AttributeError: return None
你可以这样使用:
x = Dict({'a':0, 'b':1})
print(x['a'], x.a)
print(x['c'], x.c)
问题是这不能递归地应用:
x = Dict({'a':{'aa':0x00}, 'b':1})
print(x['a'], x.a)
print(x.a['aa'])
print(x.a.aa) # AttributeError: 'dict' object has no attribute 'aa'
如何解决这个问题?
让我们考虑一下您的需求。首先,你想要一些东西,为丢失的键返回None
,即defaultdict
类行为。然而,在实际代码中,您会发现即使是defaultdict
也常常太神奇了。通常您希望知道键丢失的时间,而不是静默地返回None
,而不是"崩溃整个应用程序"。你可以捕获异常:
try:
di[key]
except KeyError:
# handle missing key
第二,需要属性访问。这是可以理解的,因为写di.a
比写di['a']
要好得多(特别是在我的芬兰语键盘和许多其他键盘上,在修改键后面有方括号!)然而,将属性访问和项访问(类似字典的行为)混合到同一个对象中是有问题的。例如,考虑您的Dict
。如果有人做了呢
di = Dict()
di['keys'] = ['C#', 'D']
di.keys() # TypeError: 'list' object is not callable
现在,您的对象不再作为字典正常工作。同样的问题也适用于其他的字典方法。我猜你可以编写__setitem__()
和__setattribute__()
保护来防止覆盖字典方法,但它开始变得复杂。
在我看来,你应该决定你是想要项目访问还是属性访问,而不是试图实现两者。如果需要属性,数据类是很好的选择(您可以实现__getattr__()
以返回缺失属性的None
)。如果你想要访问项目,只需使用defaultdict
。