Python n'a pas de type frozendict intégré. Il s'avère que cela ne serait pas utile trop souvent (même si cela le serait probablement encore plus souvent frozenset
).
La raison la plus courante de vouloir un tel type est lorsque la fonction de mémorisation appelle des fonctions avec des arguments inconnus. La solution la plus courante pour stocker un équivalent hachable d'un dict (où les valeurs sont hachables) est quelque chose comme tuple(sorted(kwargs.iteritems()))
.
Cela dépend du fait que le tri n'est pas un peu fou. Python ne peut pas promettre que le tri aboutira à quelque chose de raisonnable ici. (Mais cela ne peut pas promettre grand-chose d'autre, alors ne vous inquiétez pas trop.)
Vous pouvez facilement créer une sorte de wrapper qui fonctionne un peu comme un dict. Cela pourrait ressembler à quelque chose comme
import collections
class FrozenDict(collections.Mapping):
"""Don't forget the docstrings!!"""
def __init__(self, *args, **kwargs):
self._d = dict(*args, **kwargs)
self._hash = None
def __iter__(self):
return iter(self._d)
def __len__(self):
return len(self._d)
def __getitem__(self, key):
return self._d[key]
def __hash__(self):
# It would have been simpler and maybe more obvious to
# use hash(tuple(sorted(self._d.iteritems()))) from this discussion
# so far, but this solution is O(n). I don't know what kind of
# n we are going to run into, but sometimes it's hard to resist the
# urge to optimize when it will gain improved algorithmic performance.
if self._hash is None:
hash_ = 0
for pair in self.items():
hash_ ^= hash(pair)
self._hash = hash_
return self._hash
Cela devrait très bien fonctionner:
>>> x = FrozenDict(a=1, b=2)
>>> y = FrozenDict(a=1, b=2)
>>> x is y
False
>>> x == y
True
>>> x == {'a': 1, 'b': 2}
True
>>> d = {x: 'foo'}
>>> d[y]
'foo'
__hash__
méthode pourrait être légèrement améliorée. Utilisez simplement une variable temporaire lors du calcul du hachage et ne la définissez qu'uneself._hash
fois que vous avez la valeur finale. De cette façon, un autre thread obtenant un hachage pendant que le premier calcule fera simplement un calcul redondant, plutôt que d'obtenir une valeur incorrecte.Curieusement, bien que nous ayons le rarement utile
frozenset
en python, il n'y a toujours pas de mappage figé. L'idée a été rejetée dans PEP 416 - Ajouter un type intégré frozendict . L'idée peut être revisitée en Python 3.9, voir PEP 603 - Ajout d'un type de Frozenmap aux collections .Donc, la solution python 2 à cela:
Semble toujours être un peu boiteux:
En python3, vous avez l'option de ceci :
Maintenant, la configuration par défaut peut être mise à jour de manière dynamique, mais reste immuable là où vous voulez qu'elle soit immuable en passant le proxy à la place.
Donc les changements dans la
default_config
mise à jourDEFAULTS
comme prévu, mais vous ne pouvez pas écrire dans l'objet proxy de mappage lui-même.Certes, ce n'est pas tout à fait la même chose qu'un "dict immuable, hachable" - mais c'est un substitut décent étant donné le même genre de cas d'utilisation pour lesquels nous pourrions vouloir un frozendict.
la source
def foo(config=MappingProxyType({'a': 1})):
? Votre exemple permet toujours une modification globaledefault_config
.config = default_config = {'a': 1}
est une faute de frappe.En supposant que les clés et les valeurs du dictionnaire sont elles-mêmes immuables (par exemple des chaînes), alors:
la source
dict(t)
Il n'y en a pas
fronzedict
, mais vous pouvez utiliserMappingProxyType
celui qui a été ajouté à la bibliothèque standard avec Python 3.3:la source
TypeError: can't pickle mappingproxy objects
MappingProxyType
est toujours insurmontable.Voici le code que j'utilise. J'ai sous-classé frozenset. Les avantages de ceci sont les suivants.
Mise à jour du 21 janvier 2015: le morceau de code original que j'ai publié en 2014 utilisait une boucle for pour trouver une clé qui correspondait. C'était incroyablement lent. Maintenant, j'ai mis en place une implémentation qui tire parti des fonctionnalités de hachage de frozenset. Les paires clé-valeur sont stockées dans des conteneurs spéciaux où les fonctions
__hash__
et__eq__
sont basées uniquement sur la clé. Ce code a également été officiellement testé à l'unité, contrairement à ce que j'ai publié ici en août 2014.Licence de type MIT.
la source
Item
pour être le hachage de la clé est un hack soigné!diff(diff({key}))
est toujours linéaire dans la taille de FrozenDict, tandis que le temps d'accès régulier aux dict est constant dans le cas moyen.Je pense à frozendict à chaque fois que j'écris une fonction comme celle-ci:
la source
optional_dict_parm = optional_dict_parm or {}
types.MappingProxyType
({})
Vous pouvez utiliser
frozendict
fromutilspie
package comme:Selon le document :
la source
Installez frozendict
Utilise le!
la source
Oui, c'est ma deuxième réponse, mais c'est une approche complètement différente. La première implémentation était en python pur. Celui-ci est en Cython. Si vous savez comment utiliser et compiler des modules Cython, c'est aussi rapide qu'un dictionnaire ordinaire. Environ 0,04 à 0,06 micro-s pour récupérer une seule valeur.
Ceci est le fichier "Frozen_dict.pyx"
Voici le fichier "setup.py"
Si Cython est installé, enregistrez les deux fichiers ci-dessus dans le même répertoire. Accédez à ce répertoire dans la ligne de commande.
Et vous devriez avoir fini.
la source
Le principal inconvénient de
namedtuple
est qu'il doit être spécifié avant d'être utilisé, il est donc moins pratique pour les cas à usage unique.Cependant, il existe une solution de contournement pratique qui peut être utilisée pour gérer de nombreux cas de ce type. Disons que vous voulez avoir un équivalent immuable du dict suivant:
Cela peut être émulé comme ceci:
Il est même possible d'écrire une fonction auxiliaire pour automatiser cela:
Bien sûr, cela ne fonctionne que pour les dicts plats, mais il ne devrait pas être trop difficile d'implémenter une version récursive.
la source
getattr(fa, x)
place defa[x]
, aucunekeys
méthode au bout de vos doigts, et toutes les autres raisons pour lesquelles un mapping peut être souhaitable.Sous-classement
dict
Je vois ce modèle dans la nature (github) et je voulais le mentionner:
exemple d'utilisation:
Avantages
get()
,keys()
,items()
(iteritems()
sur py2) et toutes les friandises dedict
sortir de la boîte sans les mettre en œuvre explicitementdict
ce qui signifie performance (dict
est écrit en c en CPython)isinstance(my_frozen_dict, dict)
renvoie True - bien que python encourage l' utilisation de nombreux paquets de type canardisinstance()
, cela peut économiser de nombreux ajustements et personnalisationsLes inconvénients
__hash__
un peu plus vite.la source
__setitem__
et l'héritagedict
sont incroyablement rapides par rapport à de nombreuses alternatives.Une autre option est la
MultiDictProxy
classe dumultidict
package.la source
J'avais besoin d'accéder à des clés fixes pour quelque chose à un moment donné pour quelque chose qui était une sorte de genre de chose globalement constant et je me suis installé sur quelque chose comme ceci:
Utilisez-le comme
AVERTISSEMENT: je ne le recommande pas pour la plupart des cas d'utilisation car cela fait des compromis assez sévères.
la source
En l'absence de prise en charge de la langue native, vous pouvez le faire vous-même ou utiliser une solution existante. Heureusement, Python rend très simple l'extension de leurs implémentations de base.
la source