2009-08-14 28 views
14

Necesito una función de actualización profunda de Python 3.1 para diccionarios (una función que actualizará recursivamente los diccionarios secundarios que están dentro de un diccionario principal).Python y diccionario como objeto

Pero creo que, en el futuro, mi función podría tener que tratar con objetos que se comportan como diccionarios pero no lo son. Y además quiero evitar usar isinstance y type (porque se consideran malos, como puedo leer en casi todos los blogs de Pythonista).

Pero la tipificación de pato es parte de la filosofía de Python, así que ¿cómo podría verificar si un objeto es similar a un diccionario?

Gracias!

Editar: Gracias a todos por las respuestas. Por si acaso, la función que codifiqué se puede encontrar en este lugar: http://blog.cafeaumiel.com/public/python/dict_deep_update.py

+0

Siempre tome declaraciones generales en los blogs con un grano de sal. Soy un gran admirador de la tipificación de patos y el enfoque "más fácil de pedir perdón que de permiso", pero vea PEP 3119 con respecto a ABC como en mi respuesta a continuación para una discusión más matizada: http://www.python.org/dev/ peps/pep-3119/ – Anon

+0

[Pregunta relacionada] (http://stackoverflow.com/questions/8601268/python-class-hathat-acts-as-mapping-for-unpacking) - podría probar la existencia de lo mencionado métodos allí. – jvdm

Respuesta

15

Mira la nueva clases (en 3.x) de base abstracta (ABC) en el módulo de colecciones:

http://docs.python.org/3.1/library/collections.html

me consideraría consultar con isinstance contra Mapeo como en el siguiente:

>>> import collections 
>>> isinstance({},collections.Mapping) 
True 

Luego, si crea su propia clase similar a un dictado, haga colecciones. Asigne una de sus bases.

La otra ruta es intentar y detectar las excepciones para las operaciones del diccionario, pero con la recursión de la que habla, preferiría verificar primero el tipo de base que tratar de descifrar qué dict o subdict u otro dict el miembro estaba o no estaba allí para lanzar una excepción.

Edición para agregar: El beneficio de verificar contra el Cartografía ABC en vez de contra dict es que la misma prueba funcionará para las clases dict-like independientemente de si subclasifican o no, así que es más flexible, por las dudas.

+0

Absolutamente a la derecha: los ABC están ahí para permitirle "programar contra una interfaz, no una implementación", ¡así como el Gof4 lo insta a hacerlo! -) –

+0

a su manera, haciendo eso suena bien. Pero, ¿qué son Gof4? – thomas

+1

Gof4 es la abreviatura de "Gang of Four", que es lo que comúnmente llaman los autores de este libro, ya que es más fácil que decir todos sus nombres: http://www.amazon.com/Design-Patterns-Object-Oriented-Addison -Wesley-Professional/dp/0201633612/ref = sr_1_1? Ie = UTF8 & qid = 1250260861 & sr = 8-1 – Anon

2

, no hay nada de malo en ello y se usa de forma rutinaria en el código que requiere recursión.

Si por diccionario quiere decir que la clase del objeto hereda del dict, isinstance también devolverá True.

>>> class A(dict): 
    pass 

>>> a = A() 
>>> isinstance(a, dict) 
True 
+2

El fac es que no quiero codificar contra la clase * dict * sino contra su interfaz :) – thomas

1

pato escribir es donde se hace lo que quiere hacer, y hacer frente a las consecuencias si los objetos no se comportan de la manera que se esperaba que lo hicieran.

Quiere comprobar si algo es similar a un dictado, y actualizarlo si es así, ¿no? Simplemente llame al método de actualización del objeto y maneje la Excepción que recibe si no existe dicho método.

Por supuesto, esto no funcionará si se trata de objetos de clases personalizadas que tienen métodos de actualización que hacen algo completamente diferente: no estoy muy seguro de cómo lidiar con eso.

+0

No uso el método de actualización de la clase * dict *. en cambio, recorro manualmente el diccionario y cuando un valor es un objeto como un diccionario, trato de llamar recursivamente a mi función para actualizarla. – thomas

0

Si también tiene que manejar clases personalizadas que se comportan como diccionarios pero no están subclases de dict, puede usar getattr para obtener la función que necesita.

# loop 
# ... more code 
someObject = getObject(..) 
try: 
    getattr(someObject, "update")("someValue") 
except AttributeError: 
    # Wasn't a type we can handle 
1

Bueno, para actualizar recursivamente un diccionario, debe llamar al método de 'elementos' para iterar en él.

por lo que sugiero, que acaba de hacer:

try : 
    for key, value in data.items() : 
     # recursive call 
except AttributeError : 
    # handling the trouble 
1

me gusta para comprobar la '__setitem__' método mágico ... esto es lo que permite que el foo [ 'bar'] = comportamiento Baz .

if getattr(obj, '__setattr__'): 
    obj[key] = val 

Aquí es el python 2.7 docs

Cuestiones relacionadas