簡體   English   中英

類似於dict的類,它使用轉換后的鍵

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM