Неизменный словарь с парами ключ-объект Python

У меня есть словарь, заполненный парами ключ-объект. Я хочу сделать словарь неизменным, и я подумал, что лучший / самый простой способ - привести его к заморозке, но frozenset(dict) а также tuple(dict) хранит только ключи.

С помощью frozenset(dict.items()) Я, кажется, получил Frozenset с парами ключ-объект, но я не знаю, как получить значения / ключи.

У меня есть следующий код, который работает, пока "__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

Я хотел бы поблагодарить всех за их усилия и вклад.

5 ответов

Вы можете создать неизменный вид словаря, используя 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]

буду работать.

Самый простой способ достичь желаемого - создать подкласс стандарта 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})

например, обновит его, но это решение может быть достаточно хорошим - оно зависит от более широких требований.

Вы можете создать класс-обертку, который принимает словарь и имеет функцию get item, но не имеет установленного элемента. Возможно, вам придется добавить несколько вещей для безопасности потоков и хэширования, но базовый класс не будет слишком сложным.

Поскольку вы упоминаете tuple(dict) в вашем исходном посте, возможно, самое простое решение для достижения желаемого:

tuple(dict.items())

Тебе необходимо 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

Он будет вести себя так же, как обычно dict пока ты не позвонишь .freeze(), Тогда это заморожено.

Другие вопросы по тегам