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"
defaultdictdespué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
defaultdicten 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
defaultdicty agregue un método que "cierre" todas las características dedefaultdict, dejando que se comporte como si fuera undictregular. 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
dictregular 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.