Di mana Saya Menjawab Pertanyaan Yang Ditanyakan
Mengapa Python tidak menawarkannya di luar kotak?
Saya menduga itu ada hubungannya dengan Zen Python : "Seharusnya ada satu - dan lebih disukai hanya satu - cara yang jelas untuk melakukannya." Ini akan menciptakan dua cara yang jelas untuk mengakses nilai dari kamus: obj['key']
danobj.key
.
Peringatan dan Kesalahan
Ini termasuk kemungkinan kurangnya kejelasan dan kebingungan dalam kode. yaitu, yang berikut ini dapat membingungkan orang lain yang akan mempertahankan kode Anda di kemudian hari, atau bahkan untuk Anda, jika Anda tidak akan kembali ke sana untuk sementara waktu. Lagi, dari Zen : "Keterbacaan penting!"
>>> KEY = 'spam'
>>> d[KEY] = 1
>>> # Several lines of miscellaneous code here...
... assert d.spam == 1
Jika d
dipakai atau KEY
didefinisikan atau d[KEY]
ditugaskan jauh dari tempat d.spam
yang digunakan, itu dapat dengan mudah menyebabkan kebingungan tentang apa yang sedang dilakukan, karena ini bukan idiom yang umum digunakan. Saya tahu itu akan berpotensi membingungkan saya.
Selain itu, jika Anda mengubah nilai KEY
sebagai berikut (tetapi tidak mengubah d.spam
), Anda sekarang mendapatkan:
>>> 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, tidak sepadan dengan usaha.
Barang-barang lainnya
Seperti yang telah dicatat orang lain, Anda dapat menggunakan objek hashable apa saja (bukan hanya string) sebagai kunci dict. Sebagai contoh,
>>> d = {(2, 3): True,}
>>> assert d[(2, 3)] is True
>>>
legal, tapi
>>> 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
>>>
tidak. Ini memberi Anda akses ke seluruh jajaran karakter yang dapat dicetak atau objek hashable lainnya untuk kunci kamus Anda, yang tidak Anda miliki ketika mengakses atribut objek. Hal ini memungkinkan keajaiban seperti metaclass objek yang di-cache, seperti resep dari Python Cookbook (Bab 9) .
Di mana saya Editorialize
Saya lebih suka estetika spam.eggs
lebih spam['eggs']
(saya pikir itu terlihat lebih bersih), dan saya benar-benar mulai mendambakan fungsi ini ketika saya bertemu namedtuple
. Tetapi kenyamanan untuk dapat melakukan hal-hal berikut ini.
>>> 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}
>>>
Ini adalah contoh sederhana, tetapi saya sering menemukan diri saya menggunakan dicts dalam situasi yang berbeda dari yang saya gunakan obj.key
notasi (yaitu, ketika saya perlu membaca prefs dari file XML). Dalam kasus lain, ketika saya tergoda untuk membuat kelas dinamis dan menampar beberapa atribut di atasnya untuk alasan estetika, saya terus menggunakan dikt untuk konsistensi untuk meningkatkan keterbacaan.
Saya yakin OP telah lama menyelesaikan ini untuk kepuasannya, tetapi jika dia masih menginginkan fungsi ini, maka saya sarankan dia mengunduh salah satu paket dari pypi yang menyediakannya:
Bunch adalah orang yang aku kenal. Subkelas daridict
, jadi Anda memiliki semua fungsi itu.
AttrDict juga terlihat seperti itu juga cukup bagus, tapi saya tidak terbiasa dengannya dan belum melihat sumbernya sedetail Bunch .
- Addict dirawat secara aktif dan menyediakan akses seperti attr dan lainnya.
- Seperti disebutkan dalam komentar oleh Rotareti, Bunch telah ditinggalkan, tetapi ada garpu aktif yang disebut Munch .
Namun, untuk meningkatkan keterbacaan kodenya, saya sangat menyarankan agar dia tidak mencampur gaya notasinya. Jika dia lebih suka notasi ini maka dia hanya perlu instantiate objek dinamis, tambahkan atribut yang diinginkan untuk itu, dan menyebutnya sehari:
>>> C = type('C', (object,), {})
>>> d = C()
>>> d.spam = 1
>>> d.eggs = 2
>>> d.ham = 3
>>> assert d.__dict__ == {'spam': 1, 'eggs': 2, 'ham': 3}
Di mana Saya Memperbarui, untuk Menjawab Pertanyaan Tindak Lanjut dalam Komentar
Dalam komentar (di bawah), Elmo bertanya:
Bagaimana jika Anda ingin masuk lebih dalam? (mengacu pada tipe (...))
Meskipun saya belum pernah menggunakan use case ini (sekali lagi, saya cenderung menggunakan nested dict
, untuk konsistensi), kode berikut berfungsi:
>>> 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
sangat berguna untuk ini.