[英]A dict-like class that uses transformed keys
我想要一個類似於dict的類,它在查找時透明地使用轉換后的鍵,這樣我就可以寫了
k in d # instead of f(k) in d
d[k] # instead of d[f(k)]
d.get(k, v) # instead of d.get(f(k), v)
等等(想象一下例如f
執行某種規范化,例如f(k)
返回k.lower()
。)
似乎我可以從dict
繼承並覆蓋單個操作,但並不是說所有鍵都經過這種轉換的集中點。 這意味着我必須覆蓋所有的__contains__
, __getitem__
, get
,可能__missing__
等,這過於繁瑣且容易出錯,而不是非常有吸引力的,除非這方面的開銷遠遠超過在手動代的f(k)
用於在每次通話普通dict
。
我不確定為什么你的問題被低估了,這是一個合理的想法。 在Java中,Guava提供了幾個映射轉換實用程序,可以像您所描述的那樣提供對支持映射的視圖。 但是它們不提供Maps.transformKeys()
方法,因為它實際上不是一個非常有用的函數。 請參閱如何使用guava將Map <String,String>轉換為Map <Long,String>以及為什么Guava不提供轉換地圖鍵的方法以獲取有關原因的詳細信息。
簡而言之,在一般情況下不可能有效地提供密鑰轉換。 不是創建您想象的復雜且可能不一致的數據結構,最好的做法是創建一個應用鍵轉換的新dict ,例如:
{ f(k): v for k, v in d.iteritems() }
那么,慣用的方法可能是使用dimo414的答案。 對於變換不純的情況(不總是在給定相同參數的情況下計算相同的結果值):
class Foo(dict):
def __init__(self, transform, *args, **kwargs):
super(Foo, self).__init__(self, *args, **kwargs)
assert isfunction(transform), u'Transform argument must be a function.'
self._transform = transform
def get(self, k, d=None):
return super(Foo, self).get(self._transform(k), d)
def __getitem__(self, item):
return super(Foo, self).__getitem__(self._transform(item))
def __contains__(self, item):
return super(Foo, self).__contains__(self._transform(item))
def __repr__(self):
return '<Foo instance {}>'.format(id(self))
測試:
>>> import datetime
>>> # {0: '0', 1: '1', 2: '2' ... 99: '99'}
>>> x = Foo(lambda x: (datetime.datetime.now() - x).seconds, ((i, str(i)) for i in range(10)))
>>> t = datetime.datetime.now()
>>> x.get(t)
'5'
>>> x[t]
'12'
不是那么乏味,但我不喜歡它的氣味(在設計方面)。
由於您希望保持與dict()
完全相同的簽名,因此我建議創建一個工廠函數來包裝TransformDict
以提供相同的簽名。
def transform_dict(transform_key):
def _transform_dict(*args, **kwargs):
return TransformDict(transform_key, *args, **kwargs)
return _transform_dict
哪個可以用作:
>>> LowerDict = transform_dict(lambda k: k.lower())
>>> lower_dict = LowerDict({'FOO': 1}, BaR=2)
TransformDict(<function <lambda> at 0x12345678>, {'foo': 1, 'bar': 2})
TransformDict
應該實現MutableMapping
抽象基類,這樣任何可能丟失的dict
方法都不會以靜默方式傳遞。 所有處理轉換鍵的方法都可以用__contains__()
, __getitem__()
__contains__()
, __getitem__()
__setitem__()
和__delitem__()
。
import collections
import sys
class TransformDict(collections.MutableMapping):
def __init__(self, __transform_key, *args, **kwargs):
self.data = dict(*args, **kwargs)
self.transform_key = __transform_key
# Key methods.
def __contains__(self, key):
key = self.transform_key(key)
return key in self.data
def __getitem__(self, key):
key = self.transform_key(key)
return self.data[key]
def __setitem__(self, key, value):
key = self.transform_key(key)
self.data[key] = value
def __delitem__(self, key):
key = self.transform_key(key)
del self.data[key]
# Operator methods.
def __iter__(self):
return iter(self.data)
def __len__(self):
return len(self.data)
def __eq__(self, other):
if isinstance(other, TransformDict):
other = other.data
return self.data == other
def __ne__(self, other):
return not (self == other)
def __repr__(self):
return "{}({!r}, {!r})".format(self.__class__.__name__, self.transform_key, self.data)
# Accessor methods.
def get(self, key, default=None):
if key in self:
return self[key]
return default
def keys(self):
return self.data.keys()
def items(self):
return self.data.items()
def values(self):
return self.data.values()
if sys.version_info[0] == 2:
def iterkeys(self):
return self.data.iterkeys()
def itervalues(self):
return self.data.itervalues()
def iteritems(self):
return self.data.iteritems()
def viewkeys(self):
return self.data.viewkeys()
def viewvalues(self):
return self.data.viewvalues()
def viewitems(self):
return self.data.viewitems()
# Mutable methods.
def clear(self):
self.data.clear()
def pop(self, key, default=KeyError):
if key in self or default is KeyError:
value = self[key]
del self[key]
return value
return default
def popitem(self):
return self.data.popitem()
def setdefault(self, key, default=None):
if key not in self:
self[key] = default
return default
return self[key]
def update(self, other):
for key for other:
self[key] = other[key]
# Miscellaneous methods.
def copy(self):
return self.__class__(self.transform_key, self.data)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.