2009-08-14 10 views
14

Ho bisogno di una funzione di aggiornamento profondo di python 3.1 per i dizionari (una funzione che aggiornerà in modo ricorsivo i dizionari figlio che si trovano all'interno di un dizionario principale).Python e dizionario come oggetto

Ma penso che in futuro la mia funzione potrebbe avere a che fare con oggetti che si comportano come dizionari ma non lo sono. E inoltre voglio evitare di usare isinstance e type (perché sono considerati cattivi, come posso leggere su quasi tutti i blog di Pythonista).

Ma la digitazione anatra fa parte della filosofia di Python, quindi come posso verificare se un oggetto è simile al dizionario?

Grazie!

Modifica: Grazie a tutti per le risposte. Nel caso in cui, la funzione che ho codificato può essere trovata in questo posto: http://blog.cafeaumiel.com/public/python/dict_deep_update.py

+0

Prenda sempre dichiarazioni coperta sui blog con un grano di sale. Sono un grande fan della digitazione anatra e dell'approccio "più facile chiedere perdono che permesso", ma vedi il PEP 3119 riguardante l'ABC come nella mia risposta per una discussione più sfumata: http://www.python.org/dev/ peps/pep-3119/ – Anon

+0

[domanda correlata] (http://stackoverflow.com/questions/8601268/python-class-that-acts-as-mapping-for-unpacking) - puoi testare l'esistenza di metodi lì. – jvdm

risposta

15

Scopri i corsi (di nuovo in 3.x) di base astratta (ABC) nel modulo di collezioni:

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

vorrei prendere in considerazione il controllo con isinstance contro Mapping come nel seguente:

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

Quindi, se si crea la propria classe dict-like, si creano le raccolte.Mappando una delle sue basi.

L'altro percorso sta provando e rilevando le eccezioni per le operazioni del dizionario, ma con la ricorrenza di cui parli, preferisco controllare prima il tipo di base piuttosto che gestire il problema di dettare o sottotitolare o altro membro era o non era lì per gettare un'eccezione.

Modifica per aggiungere: Il beneficio di controllo contro il Mapping ABC anziché contro dict è che lo stesso test funzionerà per le classi dict simile indipendentemente dal fatto o meno sottoclasse dict, in modo che sia più flessibile, per ogni evenienza.

+0

Assolutamente giusto: gli ABC sono lì per farti "programma contro un'interfaccia, non un'implementazione", proprio come il Gof4 ti spinge a! -) –

+0

per farlo suonare bene. Ma cosa sono Gof4 ?? – thomas

+1

Gof4 è l'abbreviazione di "Gang of Four", che è ciò che gli autori di questo libro sono comunemente chiamati, dal momento che è più facile che dire tutti i loro nomi: 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

utilizzare isinstance, non c'è niente di sbagliato in esso ed è usato di routine nel codice che richiede la ricorsione.

Se per dizionario si intende la classe dell'oggetto ereditata dallo dict, isinstance restituirà anche True.

>>> class A(dict): 
    pass 

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

Il fac è che non voglio codificare la classe * dict * ma contro la sua interfaccia :) – thomas

1

duck typing è dove si fa quello che si vuole fare, e affrontare le conseguenze se gli oggetti non si comportano il modo in cui vi aspettavate loro.

Si desidera controllare se qualcosa è simile a dict e aggiornarlo se lo è, giusto? Basta chiamare il metodo di aggiornamento dell'oggetto e gestire l'eccezione che si ottiene se non esiste un tale metodo.

Ovviamente, questo si riduce se si gestiscono oggetti di classe personalizzati che hanno metodi di aggiornamento che fanno qualcos'altro interamente. Non sono abbastanza sicuro di come gestirlo.

+0

Non uso il metodo di aggiornamento dalla classe * dict *. invece passo manualmente il dizionario e quando un valore è un dizionario come oggetto, provo a chiamare ricorsivamente la mia funzione per aggiornarlo. – thomas

0

Se si devono gestire anche classi personalizzate che si comportano come dizionari ma non sono sottoclasse da dict, è possibile utilizzare getattr per ottenere la funzione richiesta.

1

Bene, per aggiornare in modo ricorsivo un dizionario, è necessario chiamare il metodo 'items' per iterare su di esso.

Quindi vi consiglio, basta fare:

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

mi piace per verificare la '__setitem__' metodo magico ... questo che è ciò che permette il foo [ 'bar'] = comportamento baz .

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

Ecco la python 2.7 docs