In cui rispondo alla domanda che è stata posta
Perché Python non lo offre immediatamente?
Sospetto che abbia a che fare con lo Zen di Python : "Dovrebbe esserci un modo - e preferibilmente solo uno - ovvio per farlo." Ciò creerebbe due modi ovvi per accedere ai valori dai dizionari: obj['key']
eobj.key
.
Avvertenze e insidie
Questi includono la possibile mancanza di chiarezza e confusione nel codice. vale a dire, ciò che segue potrebbe essere fonte di confusione per qualcun altro che sta per mantenere il codice in un secondo momento, o anche per te, se non ci tornerai per un po '. Ancora una volta, dallo Zen : "La leggibilità conta!"
>>> KEY = 'spam'
>>> d[KEY] = 1
>>> # Several lines of miscellaneous code here...
... assert d.spam == 1
Se d
è istanziato o KEY
è definito o d[KEY]
è assegnato lontano da doved.spam
viene utilizzato, può facilmente creare confusione su ciò che viene fatto, poiché questo non è un linguaggio comunemente usato. So che avrebbe il potenziale per confondermi.
Inoltre, se si modifica il valore di KEY
come segue (ma manca la modifica d.spam
), ora si ottiene:
>>> KEY = 'foo'
>>> d[KEY] = 1
>>> # Several lines of miscellaneous code here...
... assert d.spam == 1
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
AttributeError: 'C' object has no attribute 'spam'
IMO, non vale la pena.
Altri oggetti
Come altri hanno già notato, puoi usare qualsiasi oggetto hash (non solo una stringa) come chiave dict. Per esempio,
>>> d = {(2, 3): True,}
>>> assert d[(2, 3)] is True
>>>
è legale, ma
>>> C = type('C', (object,), {(2, 3): True})
>>> d = C()
>>> assert d.(2, 3) is True
File "<stdin>", line 1
d.(2, 3)
^
SyntaxError: invalid syntax
>>> getattr(d, (2, 3))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: getattr(): attribute name must be string
>>>
non è. Ciò consente di accedere all'intera gamma di caratteri stampabili o altri oggetti hash per le chiavi del dizionario, che non si hanno quando si accede a un attributo oggetto. Ciò rende possibile una magia come una metaclasse di oggetti memorizzati nella cache, come la ricetta del ricettario di Python (cap. 9) .
In cui editoriale
Preferisco l'estetica di spam.eggs
over spam['eggs']
(penso che appaia più pulita), e ho davvero iniziato a desiderare questa funzionalità quando ho incontrato il namedtuple
. Ma la comodità di essere in grado di fare ciò che segue vince.
>>> KEYS = 'spam eggs ham'
>>> VALS = [1, 2, 3]
>>> d = {k: v for k, v in zip(KEYS.split(' '), VALS)}
>>> assert d == {'spam': 1, 'eggs': 2, 'ham': 3}
>>>
Questo è un semplice esempio, ma mi trovo spesso ad usare dicts in situazioni diverse rispetto a quelle usate per la obj.key
notazione (ad esempio, quando ho bisogno di leggere le preferenze da un file XML). In altri casi, dove sono tentato di creare un'istanza di una classe dinamica e di schiaffeggiarne alcuni per motivi estetici, continuo a usare un dict per coerenza al fine di migliorare la leggibilità.
Sono sicuro che l'OP ha da tempo risolto questo in modo soddisfacente, ma se vuole ancora questa funzionalità, quindi suggerisco di scaricare uno dei pacchetti da pypi che lo fornisce:
Il mazzo è quello con cui ho più familiarità. Sottoclasse didict
, quindi hai tutte quelle funzionalità.
Anche AttrDict sembra essere abbastanza buono, ma non ho familiarità con esso e non ho guardato attraverso la fonte con tutti i dettagli che ho Bunch .
- Il tossicodipendente viene attivamente mantenuto e offre un accesso simile e altro ancora.
- Come notato nei commenti di Rotareti, Bunch è stato deprecato, ma esiste un fork attivo chiamato Munch .
Tuttavia, al fine di migliorare la leggibilità del suo codice, consiglio vivamente di non mescolare i suoi stili di notazione. Se preferisce questa notazione, dovrebbe semplicemente creare un'istanza di un oggetto dinamico, aggiungere gli attributi desiderati e chiamarlo un giorno:
>>> C = type('C', (object,), {})
>>> d = C()
>>> d.spam = 1
>>> d.eggs = 2
>>> d.ham = 3
>>> assert d.__dict__ == {'spam': 1, 'eggs': 2, 'ham': 3}
In cui aggiorno, per rispondere a una domanda di follow-up nei commenti
Nei commenti (sotto), Elmo chiede:
E se vuoi approfondire? (riferito al tipo (...))
Anche se non ho mai usato questo caso d'uso (di nuovo, tendo a usare nidificato dict
, per coerenza), il seguente codice funziona:
>>> C = type('C', (object,), {})
>>> d = C()
>>> for x in 'spam eggs ham'.split():
... setattr(d, x, C())
... i = 1
... for y in 'one two three'.split():
... setattr(getattr(d, x), y, i)
... i += 1
...
>>> assert d.spam.__dict__ == {'one': 1, 'two': 2, 'three': 3}
collections.namedtuple
è molto utile per questo.