Is there a better way to create a class which is a subclass of `dict` but case-insensitive?
我想创建从dict类型继承的类,但可以使用不区分大小写的键访问数据。我实现了一个简单的方法,但我不认为使用instance.__dict__变量是一种合适的方法。有更好的方法吗?
这是我的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class MyDict(dict):
def __init__(self, *args, **kwargs):
if args:
for k, v in args[0].iteritems():
self.__dict__.update({k.lower(): v})
def __getitem__(self, k):
return self.__dict__.get(k.lower())
def __setitem__(self, k, v):
self.__dict__.update({k.lower(): v})
def __delitem__(self, k):
self.__dict__.pop(k, None)
if __name__ == '__main__':
test_0 = MyDict({'naME': 'python', 'Age': 24})
print(test_0['name']) # return 'python'
print(test_0['AGE']) # return 24
test_1 = MyDict()
test_1['StaCk'] = 23
print(test_1['stack']) # return 23
print(test_1['STACK']) # return 23 |
- super()是访问祖先方法的首选方式。
- 看看如何"完美地"重写听写
- 真的看到那个问题了。接受的答案是实现不区分大小写字典的更好方法,而不是从dict继承。除了其他内容,您还希望isinstance(MyDict(), dict)是假的,因为您的类没有dict的记录行为。李斯科夫替代原理。
- @stevejessop提供的dict的子类也不遵循lsp。例如,defaultdict未能对丢失的密钥抛出异常,并且比较两个OrderedDict实例可以返回不相等的结果,其中,与dict实例相比,它们将相等。
- @邓肯:说得对。因为标准库已经创建了一个问题,所以用户定义的类是否参与其中并不重要。反弹道导弹也是一种更好的方法来实施defaultdict和OrderedDict,但是那艘船已经开航了。
- @duncan,ordereddict.uueq_uu()与常规dict的比较不区分顺序,因此保留了lsp。请参阅pastebin.com/cfcaewfw上的示例
编辑:查看JanneKarila的链接,其中包含更好的解决方案。
不要使用self.u dict_uuuuuuuuuuuuuuuu,它有一个与dict无关的特殊含义,您应该使用super()来调用超类上的相应函数。
例如。,
1 2 3 4
| def __setitem__(self, k, v):
if hasattr(k, 'lower'):
k = k.lower()
return super(MyDict, self).__setitem__(k, v) |
- imho,在这种情况下,最好让hasattr()退房,只让return super(MyDict, self).__setitem__(k.lower(), v)退房,并允许在适当的情况下提出例外——EAFP与LBYL的辩论。还要注意,JanneKarila链接中的答案没有任何错误检查。
- 我想是味觉问题吧。在我看来,字典不区分大小写并不意味着非字符串键停止工作。
- 在这种情况下,您仍然可以假定它是一个带有lower()方法的字符串,并在该方法内捕获异常。
- @马蒂诺:EAFP有一个问题,通常(我认为在本例中)是很小的问题,但仍然很烦人。假设实现了lower,但抛出了AttributeError,那么您不一定想抓住它,最好让它传播。所以,我认为这是一个品味问题,问题是你是否证明,如果调用k.lower()抛出AttributeErrorvs"如果lower不存在",vs"如果lower不存在或不可调用",或者其他什么,k是未经修改的密钥。所以这不是关于代码结构,而是关于首选行为。
- @SteveJessop:在Mecould看来,如果该键有一个lower()方法,可以在不引发AttributeError异常的情况下调用,那么它就是。第二,EAFP风格的版本可能只是try:、return super(MyDict, self).__setitem__(k.lower(), v)、except AttributeError:、return super(MyDict, self).__setitem__(k, v)。