【发布时间】:2013-08-19 15:47:22
【问题描述】:
试图创建一个自定义的不区分大小写的字典,我遇到了以下不方便和(从我的角度来看)意外的行为。如果从dict 派生类,则在转换回dict 时将忽略重载的__iter__、keys、values 函数。我将其浓缩为以下测试用例:
import collections
class Dict(dict):
def __init__(self):
super(Dict, self).__init__(x = 1)
def __getitem__(self, key):
return 2
def values(self):
return 3
def __iter__(self):
yield 'y'
def keys(self):
return 'z'
if hasattr(collections.MutableMapping, 'items'):
items = collections.MutableMapping.items
if hasattr(collections.MutableMapping, 'iteritems'):
iteritems = collections.MutableMapping.iteritems
d = Dict()
print(dict(d)) # {'x': 1}
print(dict(d.items())) # {'y': 2}
keys,values 和 __iter__,__getitem__ 的值不一致,仅用于演示实际调用了哪些方法。
documentation for dict.__init__ 说:
如果给出了一个位置参数并且它是一个映射对象,一个 字典是使用与映射相同的键值对创建的 目的。否则,位置参数必须是迭代器对象。
我猜这与第一句话有关,也可能与内置词典的优化有关。
为什么对dict(d) 的调用不使用keys、__iter__ 中的任何一个?
是否可以以某种方式重载“映射”以强制 dict 构造函数使用我的键值对表示?
我为什么用这个?对于不区分大小写但保留字典的字典,我想:
- 在内部存储 (lowercase => (original_case, value)),同时显示为 (any_case => value)。
- 从
dict派生,以便使用一些使用isinstance检查的外部库代码 - 不使用 2 个字典查找:lower_case=>original_case,后跟 original_case=>value(这是我现在正在做的解决方案)
如果您对申请案例感兴趣:here is corresponding branch
【问题讨论】:
-
为什么要制作继承字典,下次将其转换回简单的 dict 对象时?我的意思是,一旦你使用
dict(d),它就会变回普通字典。你应该使用:d.items() -
作为一种固有类型,重新定义
dict的语义肯定会在其他地方引起一些惊讶(如果不是彻底破坏)。 -
我不太明白为什么这个问题被标记为主要基于意见。第二个答案和第一条评论是(无论如何它甚至得到了赞成)。接受的答案虽然陈述了“事实”,但由于实施细节,这是不可能的。此外,这个问题的答案远非显而易见,因为在面向对象的语言中,这是出乎意料的行为,不可能覆盖字典
__iter__。
标签: python dictionary overloading subclassing