python python-3.x wrapper defaultdict

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:

  1. 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, {}) en mapping.get(k, {}) lugar. Esto es simplemente terrible.

  2. "Freeze" defaultdict después de que la estructura de datos esté completamente inicializada, al convertirla en dict . (Sé que no está realmente congelado, pero confío en que el código del cliente no escriba realmente la mapping[k] = v .) Inelegante, y un gran impacto en el rendimiento.

  3. Envolver defaultdict en una interfaz de dict . ¿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).

  4. Subclase defaultdict y agregue un método que "cierre" todas las características de defaultdict , dejando que se comporte como si fuera un dict 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.

  5. 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.