【问题标题】:Immutable Dictionary with key-object pairs Python具有键-对象对 Python 的不可变字典
【发布时间】:2016-08-04 14:35:57
【问题描述】:

我有一本包含键-对象对的字典。我想让字典不可变,我认为最好/最简单的方法是将其转换为frozenset,但frozenset(dict)tuple(dict) 只存储键。

使用frozenset(dict.items()),我似乎得到了一个包含键-对象对的冻结集,但我不知道如何检索值/键。

只要“__obfuscators”是字典,我就有以下代码可以工作

def obfuscate_value(self, key, value):
    obfuscator = self.__obfuscators.get(key)
    if obfuscator is not None:
        return obfuscator.obfuscate_value(value)
    else:
        return value

我尝试了这个,试图让它与冻结集一起工作:

def obfuscate_value(self, key, value):
    try:
        obfuscator = self.__obfuscators[key]
    except:
        return value
    return obfuscator.obfuscate_value(value)

但这给出了frozenset does not have \__getitem__self.__obfuscators.__getattribute__(key) 总是说它没有属性(因为我假设这会搜索一个名为 key 的函数) 有没有更好的方法使字典不可变或者如何根据键检索对象?

编辑: 我最终使用tuple(obfuscator.items()) 将字典转换为一个元组 然后自己写了找值函数:

def find_obfuscator(self, key):
    for item in self.__obfuscators:
        x, y = item
        if self.case_insensitive:
            if x.lower() == key.lower():
                return y
        else:
            if x == key:
                return y

我要感谢大家的努力和投入。

【问题讨论】:

  • 子类化collections.Mapping 或使用Mappingproxy 怎么样。据我所知,两者都是不可变的(对于给定的不可变值)。
  • 这能回答你的问题吗? What would a "frozen dict" be?

标签: python python-2.7 dictionary frozenset


【解决方案1】:

您可以使用types.MappingProxyType 创建字典的不可变视图:

from types import MappingProxyType
d = { 'a': 1 }
fd = MappingProxyType(d)
fd['a']
#output:
1

fd['a'] = 2
#output:
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'mappingproxy' object does not support item assignment

请注意,您仍然可以更改 vaule 对象,因此:

d = { 'a': [1] }
fd = MappingProxyType(d)
fd['a'].append(2)
fd['a']
#output:
[1,2]

会起作用的。

【讨论】:

    【解决方案2】:

    我能想到的实现您想要的最简单的方法是继承标准 dict 类型并覆盖其 __setitem__ 方法:

    class MyDict(dict):
        def __setitem__(self, key, value):
            raise NotImplementedError("This is a frozen dictionary")
    

    这允许您创建以后无法通过项目分配更改的字典:

    d = MyDict({1: 2, 3: 4})
    

    或者,等效地:

    d = MyDict([(1, 2), (3, 4)])
    

    然后,dict 会像标准 dict 一样打印出来:

    {1: 2, 3: 4}
    

    但是当您尝试更改一个值(或添加一个新值)时:

    d[1] = 15
    ---------------------------------------------------------------------------
    NotImplementedError                       Traceback (most recent call last)
    <ipython-input-21-a22420992053> in <module>()
    ----> 1 d[1] = 34
    
    <ipython-input-18-03f266502231> in __setitem__(self, key, value)
          1 class MyDict(dict):
          2     def __setitem__(self, key, value):
    ----> 3         raise NotImplementedError("This is a frozen dictionary")
    
    NotImplementedError: This is a frozen dictionary
    

    但请注意,这并非完全不可变:

    d.update({1:17})
    

    例如,将对其进行更新,但此解决方案可能已经足够好 - 它取决于更广泛的要求。

    【讨论】:

      【解决方案3】:

      您可以创建一个包装类,该类接受字典并具有获取项目功能但没有设置项目。您可能需要为线程安全和散列添加一些东西,但基本类不会太难。

      【讨论】:

      • 我确实考虑过这一点,但我希望有一个比制作自己的自定义字典类更容易/更快的解决方案。特别是因为我现在看起来很接近,因为我有一个带有键对象对的冻结集,但我就是无法访问它们,或者至少我不知道如何
      【解决方案4】:

      由于您在原始帖子中提到tuple(dict),因此实现您想要的最简单的解决方案可能就是:

      tuple(dict.items())
      

      【讨论】:

      • 使用这个选项,我仍然面临与frozenset(dict.items()) 相同的问题。如何根据键访问值?
      • 当我再次考虑这个选项时,我意识到这可能是更简单的解决方案,如果我自己制作搜索功能,因为所有其他选项都不是更简单
      【解决方案5】:

      您需要能够冻结的dict?你可以简单地做一个:

      class FrozenDict(dict):
          def __init__(self, *args, **kwargs):
              self._frozen = False
              dict.__init__(self, *args, **kwargs)
          def freeze(self):
              self._frozen = True
          def __setitem__(self, key, value):
              if (self._frozen):
                  raise TypeError("Attempted assignment to a frozen dict")
              else:
                  return dict.__setitem__(self, key, value)
      
      a = FrozenDict({7:8})
      a[5] = 6
      print(a)
      a.freeze()
      a[3] = 2 # raises TypeError
      

      在您调用 .freeze() 之前,它的行为与通常的 dict 完全相同。然后它就被冻结了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-08-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多