python - Exponer `defaultdict` como un` dict` regular
defaultdict python (3)
Podría hacer una clase que contenga una referencia a su dictado e impedir que setitem ()
from collections import Mapping
class MyDict(Mapping):
def __init__(self, d):
self.d = d;
def __getitem__(self, k):
return self.d[k]
def __iter__(self):
return self.__iter__()
def __setitem__(self, k, v):
if k not in self.d.keys():
raise KeyError
else:
self.d[k] = v
Estoy usando defaultdict(set)
para rellenar una asignación interna en una estructura de datos muy grande. Una vez rellenado, toda la estructura (incluida la asignación) se expone al código del cliente. En ese momento, no quiero que nadie modifique el mapeo.
Y nadie lo hace, intencionalmente. Pero a veces, el código del cliente puede referirse accidentalmente a un elemento que no existe. En ese momento, un diccionario normal hubiera generado KeyError
, pero dado que la asignación es por defaultdict
, simplemente crea un nuevo elemento (un conjunto vacío) en esa clave. Esto es bastante difícil de atrapar, ya que todo sucede en silencio. Pero necesito asegurarme de que esto no suceda (la semántica en realidad no se rompe, pero el mapeo crece a un tamaño enorme).
¿Qué tengo que hacer? Puedo ver estas opciones:
Encuentre todas las instancias en el código de cliente actual y futuro donde se realiza una búsqueda de diccionario en la asignación, y
mapping.get(k, {})
enmapping.get(k, {})
lugar. Esto es simplemente terrible."Freeze"
defaultdict
después de que la estructura de datos esté completamente inicializada, al convertirla endict
. (Sé que no está realmente congelado, pero confío en que el código del cliente no escriba realmente lamapping[k] = v
.) Inelegante, y un gran impacto en el rendimiento.Envolver
defaultdict
en una interfaz dedict
. ¿Qué es una manera elegante de hacer eso? Sin embargo, me temo que el impacto en el rendimiento puede ser enorme (esta búsqueda es muy utilizada en bucles ajustados).Subclase
defaultdict
y agregue un método que "cierre" todas las características dedefaultdict
, dejando que se comporte como si fuera undict
regular. Es una variante de 3 arriba, pero no estoy seguro si es más rápido. Y no sé si es factible sin confiar en los detalles de la implementación.Use el
dict
regular en la estructura de datos, reescribiendo todo el código para verificar primero si el elemento está en el diccionario y agregándolo si no lo está. No está bien.
Una vez que haya terminado de rellenar su sentencia predeterminada, simplemente puede crear un dictado regular a partir de ella:
my_dict = dict(my_default_dict)
Por supuesto, el dict regular está efectivamente congelado.
Si su dictamen predeterminado es un dictado recursivo predeterminado, vea esta respuesta que utiliza una solución recursiva.
defaultdict
documentos de defaultdict
dicen para default_factory
:
Si el atributo default_factory es None, esto genera una excepción KeyError con la clave como argumento.
¿Qué sucede si simplemente configura el valor por defecto de su valor por defecto en None
? P.ej,
>>> d = defaultdict(int)
>>> d[''a''] += 1
>>> d
defaultdict(<type ''int''>, {''a'': 1})
>>> d.default_factory = None
>>> d[''b''] += 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: ''b''
>>>
No estoy seguro de si este es el mejor enfoque, pero parece funcionar.