Saya merasa lebih nyaman untuk mengakses kunci dikt sebagai obj.foo
pengganti obj['foo']
, jadi saya menulis cuplikan ini:
class AttributeDict(dict):
def __getattr__(self, attr):
return self[attr]
def __setattr__(self, attr, value):
self[attr] = value
Namun, saya berasumsi bahwa pasti ada alasan mengapa Python tidak menyediakan fungsi ini di luar kotak. Apa yang akan menjadi peringatan dan perangkap mengakses kunci dikt dengan cara ini?
python
dictionary
syntax
attributes
Izz ad-Din Ruhulessin
sumber
sumber
collections.namedtuple
sangat berguna untuk ini.easydict.EasyDict
Jawaban:
Cara terbaik untuk melakukan ini adalah:
Beberapa pro:
.keys()
. Berfungsi dengan baik. Kecuali - tentu saja - Anda memberikan beberapa nilai kepada mereka, lihat di bawah)AttributeError
bukanKeyError
Cons:
.keys()
akan berfungsi dengan baik jika ditimpa oleh data yang masukE1123(unexpected-keyword-arg)
danE1103(maybe-no-member)
Penjelasan singkat tentang cara kerjanya
__dict__
.__dict__
harus "hanya dict biasa", sehingga kami dapat menetapkan subkelas apa pundict()
untuk kamus internal.AttrDict()
contoh kami instantiating (seperti yang kita lakukan__init__
).super()
's__init__()
metode kami memastikan bahwa itu (sudah) berperilaku persis seperti kamus, karena fungsi yang memanggil semua kamus Instansiasi kode.Salah satu alasan mengapa Python tidak menyediakan fungsi ini di luar kotak
Seperti yang tercantum dalam daftar "kontra", ini menggabungkan namespace dari kunci yang disimpan (yang mungkin berasal dari data yang sewenang-wenang dan / atau tidak dipercaya!) Dengan namespace atribut metode dict bawaan. Sebagai contoh:
sumber
.
, Anda tidak dapat melanggar aturan bahasa :) Dan saya tidak ingin secaraAttrDict
otomatis mengkonversi bidang yang mengandung ruang menjadi sesuatu yang berbeda.Anda dapat memiliki semua karakter string hukum sebagai bagian dari kunci jika Anda menggunakan notasi array. Sebagai contoh,
obj['!#$%^&*()_']
sumber
What would be the caveats and pitfalls of accessing dict keys in this manner?
(sebagai atribut), dan jawabannya adalah bahwa sebagian besar karakter yang ditampilkan di sini tidak dapat digunakan.Dari pertanyaan SO lainnya ini ada contoh implementasi yang bagus yang menyederhanakan kode Anda yang ada. Bagaimana tentang:
Jauh lebih ringkas dan tidak meninggalkan ruang untuk ekstra masuk ke
__getattr__
dan__setattr__
fungsi Anda di masa depan.sumber
d = AttributeDict(foo=1)
.d.bar = 1
atribut bar disimpan di dalam atribut dict tetapi tidak dalam dict itu sendiri. pencetakand
hanya menunjukkan item foo.d = AttributeDict(foo=1);d.bar = 1;print d
=>{'foo': 1, 'bar': 1}
Bekerja untuk saya!__getattr__
metode yang memunculkanAttributeError
jika atribut yang diberikan tidak ada, jika tidak hal-hal sepertigetattr(obj, attr, default_value)
tidak berfungsi (yaitu tidak kembalidefault_value
jikaattr
tidak ada padaobj
)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!"
Jika
d
dipakai atauKEY
didefinisikan ataud[KEY]
ditugaskan jauh dari tempatd.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 mengubahd.spam
), Anda sekarang mendapatkan: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,
legal, tapi
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
lebihspam['eggs']
(saya pikir itu terlihat lebih bersih), dan saya benar-benar mulai mendambakan fungsi ini ketika saya bertemunamedtuple
. Tetapi kenyamanan untuk dapat melakukan hal-hal berikut ini.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 .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:
Di mana Saya Memperbarui, untuk Menjawab Pertanyaan Tindak Lanjut dalam Komentar
Dalam komentar (di bawah), Elmo bertanya:
Meskipun saya belum pernah menggunakan use case ini (sekali lagi, saya cenderung menggunakan nested
dict
, untuk konsistensi), kode berikut berfungsi:sumber
Caveat emptor: Untuk beberapa alasan, kelas-kelas seperti ini tampaknya merusak paket multi-pemrosesan. Saya baru saja berjuang dengan bug ini untuk sementara waktu sebelum menemukan SO ini: Menemukan pengecualian dalam python multiprocessing
sumber
Anda bisa menarik kelas kontainer yang nyaman dari perpustakaan standar:
untuk menghindari harus menyalin bit kode. Tidak ada akses kamus standar, tetapi mudah mendapatkannya kembali jika Anda benar-benar menginginkannya. Kode dalam argparse sederhana,
sumber
types.SimpleNamespace
docs.python.org/dev/library/types.html#types.SimpleNamespaceBagaimana jika Anda menginginkan kunci yang merupakan metode, seperti
__eq__
atau__getattr__
?Dan Anda tidak akan dapat memiliki entri yang tidak dimulai dengan huruf, jadi gunakan
0343853
sebagai kunci keluar.Dan bagaimana jika Anda tidak ingin menggunakan string?
sumber
pickle.dump
menggunakan__getstate__
tuple dapat digunakan kunci dict. Bagaimana Anda mengakses tuple dalam konstruk Anda?
Juga, namedtuple adalah struktur yang nyaman yang dapat memberikan nilai melalui akses atribut.
sumber
Bagaimana dengan Prodict , kelas Python kecil yang saya tulis untuk mengatur semuanya :)
Plus, Anda mendapatkan penyelesaian kode otomatis , instantiasi objek rekursif , dan konversi tipe otomatis !
Anda dapat melakukan persis apa yang Anda minta:
Contoh 1: Ketik mengisyaratkan
Contoh 2: Konversi tipe otomatis
sumber
Itu tidak bekerja secara umum. Tidak semua kunci dict yang valid membuat atribut yang dapat dialamatkan ("kunci"). Jadi, Anda harus berhati-hati.
Objek Python pada dasarnya adalah kamus. Jadi saya ragu ada banyak performa atau penalti lainnya.
sumber
Ini tidak menjawab pertanyaan awal, tetapi harus bermanfaat bagi orang-orang yang, seperti saya, berakhir di sini ketika mencari lib yang menyediakan fungsi ini.
Kecanduan itu adalah lib yang bagus untuk ini: https://github.com/mewwts/addict menangani banyak masalah yang disebutkan dalam jawaban sebelumnya.
Contoh dari dokumen:
Dengan pecandu:
sumber
Saya menemukan diri saya bertanya-tanya apa keadaan saat ini "kunci dict sebagai attr" di ekosistem python. Seperti yang ditunjukkan oleh beberapa komentator, ini mungkin bukan sesuatu yang ingin Anda buat sendiri dari awal , karena ada beberapa perangkap dan footgun, beberapa di antaranya sangat halus. Juga, saya tidak akan merekomendasikan menggunakan
Namespace
sebagai kelas dasar, saya sudah jalan itu, itu tidak cantik.Untungnya, ada beberapa paket sumber terbuka yang menyediakan fungsi ini, siap untuk dipasang! Sayangnya, ada beberapa paket. Ini sinopsisnya, per Desember 2019.
Peserta (komitmen terkini untuk dikuasai | #commits | #contribs | coverage%):
Tidak lagi dipertahankan atau kurang terawat:
Saat ini saya merekomendasikan munch atau pecandu . Mereka memiliki komitmen, kontributor, dan rilis terbanyak, menunjukkan basis kode sumber terbuka yang sehat untuk masing-masing. Mereka memiliki readme.md yang tampak bersih, cakupan 100%, dan serangkaian tes yang bagus.
Saya tidak punya anjing dalam perlombaan ini (untuk saat ini!), Selain telah memutar kode dict / attr saya sendiri dan membuang banyak waktu karena saya tidak mengetahui semua opsi ini :). Saya dapat berkontribusi untuk pecandu / mengunyah di masa depan karena saya lebih suka melihat satu paket yang solid daripada sekelompok yang terfragmentasi. Jika Anda menyukainya, berkontribusi! Secara khusus, sepertinya pengunyah dapat menggunakan lencana codecov dan pecandu dapat menggunakan lencana versi python.
pecandu pro:
pecandu kontra:
typing.Dict
jika Andafrom addict import Dict
pro mengunyah:
kontra mengunyah:
Di mana saya Editorialize
Beberapa bulan yang lalu, ketika saya menggunakan editor teks untuk menulis python, pada proyek dengan hanya saya atau pengembang lain, saya menyukai gaya dict-attrs, kemampuan untuk memasukkan kunci dengan hanya mendeklarasikan
foo.bar.spam = eggs
. Sekarang saya bekerja dalam tim, dan menggunakan IDE untuk semuanya, dan saya telah menjauh dari struktur data semacam ini dan pengetikan dinamis secara umum, lebih menyukai analisis statis, teknik fungsional, dan petunjuk tipe. Saya sudah mulai bereksperimen dengan teknik ini, subclassing Pstruct dengan objek-objek desain saya sendiri:Ini memberi Anda objek yang masih berperilaku seperti dict, tetapi juga memungkinkan Anda mengakses kunci seperti atribut, dengan cara yang jauh lebih kaku. Keuntungannya di sini adalah saya (atau konsumen kode Anda yang malang) tahu persis bidang apa yang bisa dan tidak bisa ada, dan IDE bisa mengisi bidang isian secara otomatis. Juga mengelompokkan vanilla
dict
berarti serialisasi json mudah. Saya pikir evolusi berikutnya dalam ide ini akan menjadi generator protobuf kustom yang memancarkan antarmuka ini, dan ketukan yang bagus adalah Anda mendapatkan struktur data lintas-bahasa dan IPC melalui gRPC untuk hampir gratis.Jika Anda memutuskan untuk menggunakan attr-dicts, penting untuk mendokumentasikan bidang apa yang diharapkan, untuk kewarasan Anda sendiri (dan rekan tim Anda).
Jangan ragu untuk mengedit / memperbarui posting ini agar tetap terbaru!
sumber
addict
adalah tidak akan meningkatkan pengecualian ketika Anda salah mengeja atribut, karena akan mengembalikan yang baruDict
(ini diperlukan untuk foo.abc = 'bar' untuk bekerja).Berikut adalah contoh singkat dari catatan abadi menggunakan built-in
collections.namedtuple
:dan contoh penggunaan:
sumber
Hanya untuk menambahkan beberapa variasi pada jawabannya, sci-kit learn telah menerapkan ini sebagai
Bunch
:Yang Anda butuhkan adalah mendapatkan
setattr
dangetattr
metode -getattr
pemeriksaan untuk kunci dict dan langkah-langkah untuk memeriksa atribut yang sebenarnya. Inisetstaet
adalah perbaikan untuk perbaikan untuk pengawetan / pembongkaran "tandan" - jika dicabut periksa https://github.com/scikit-learn/scikit-learn/issues/6196sumber
Tidak perlu menulis sendiri sebagai setattr () dan getattr () sudah ada.
Keuntungan dari objek kelas mungkin berperan dalam definisi dan pewarisan kelas.
sumber
Saya membuat ini berdasarkan masukan dari utas ini. Saya perlu menggunakan odict, jadi saya harus mengganti get dan set attr. Saya pikir ini harus bekerja untuk sebagian besar kegunaan khusus.
Penggunaannya terlihat seperti ini:
Kelas:
Ini adalah pola yang cukup keren yang telah disebutkan di utas, tetapi jika Anda hanya ingin mengambil dikt dan mengubahnya menjadi objek yang berfungsi dengan lengkapi-otomatis dalam IDE, dll:
sumber
Rupanya sekarang ada perpustakaan untuk ini - https://pypi.python.org/pypi/attrdict - yang mengimplementasikan fungsionalitas yang tepat ini ditambah penggabungan rekursif dan pemuatan json. Mungkin patut dilihat.
sumber
Inilah yang saya gunakan
sumber
namedtuple('Args', list(args.keys()))(**args)
Anda dapat melakukannya menggunakan kelas yang baru saja saya buat. Dengan kelas ini Anda dapat menggunakan
Map
objek seperti kamus lain (termasuk serialisasi json) atau dengan notasi titik. Saya harap membantu Anda:Contoh penggunaan:
sumber
dict
metode, misalnya:m=Map(); m["keys"] = 42; m.keys()
memberiTypeError: 'int' object is not callable
.field/attribute
dan bukan amethod
, tetapi jika Anda menetapkan suatu metode sebagai gantinya, Anda dapat mengakses metode itum.method()
.Izinkan saya memposting implementasi lain, yang dibangun berdasarkan jawaban Kinvais, tetapi mengintegrasikan ide-ide dari AttributeDict yang diusulkan di http://databio.org/posts/python_AttributeDict.html .
Keuntungan dari versi ini adalah bahwa ia juga berfungsi untuk kamus bersarang:
sumber
sumber
Solusinya adalah:
sumber
Seperti yang disarankan @Henry, salah satu alasan titik-akses tidak dapat digunakan dalam dikte adalah bahwa ia membatasi nama kunci dict ke variabel python-valid, sehingga membatasi semua nama yang mungkin.
Berikut ini adalah contoh-contoh tentang mengapa titik-akses tidak akan membantu secara umum, mengingat dict,
d
:Keabsahan
Atribut berikut tidak valid dalam Python:
Gaya
Konvensi PEP8 akan memberikan batasan lunak pada penamaan atribut:
A. Nama kata kunci yang dicadangkan (atau fungsi builtin):
B. Aturan kasus tentang metode dan nama variabel :
Terkadang kekhawatiran ini muncul di perpustakaan seperti panda , yang memungkinkan akses bertitik kolom DataFrame dengan nama. Mekanisme default untuk mengatasi batasan penamaan juga notasi array - string dalam tanda kurung.
Jika kendala ini tidak berlaku untuk kasus penggunaan Anda, ada beberapa opsi pada struktur data akses bertitik .
sumber
Anda dapat menggunakan dict_to_obj https://pypi.org/project/dict-to-obj/ Itu tidak persis seperti yang Anda minta
sumber
.idea
dan file yang dibuat khusus pengguna atau IDE di file Anda.gitignore
.Ini bukan jawaban yang 'baik', tapi saya pikir ini bagus (tidak menangani dicts bersarang dalam bentuk saat ini). Cukup bungkus dict Anda dalam suatu fungsi:
Sekarang Anda memiliki sintaks yang sedikit berbeda. Untuk mengakses item dict seperti atribut lakukan
f.key
. Untuk mengakses item dict (dan metode dict lainnya) dengan cara yang biasa dilakukanf()['key']
dan kami dapat dengan mudah memperbarui dict dengan memanggil f dengan argumen kata kunci dan / atau kamusContoh
Dan itu dia. Saya akan senang jika ada yang menyarankan manfaat dan kelemahan dari metode ini.
sumber
Seperti dicatat oleh Doug ada paket Bunch yang dapat Anda gunakan untuk mencapai
obj.key
fungsionalitas. Sebenarnya ada versi yang lebih baru yang disebutNeoBunch
Ini memiliki fitur hebat yang mengubah dikt Anda menjadi objek NeoBunch melalui fungsi neobunchify -nya . Saya menggunakan banyak template Mako dan mengirimkan data sebagai objek NeoBunch membuatnya jauh lebih mudah dibaca, jadi jika Anda akhirnya menggunakan dict normal dalam program Python Anda tetapi ingin notasi titik dalam template Mako Anda dapat menggunakannya seperti itu:
Dan template Mako dapat terlihat seperti:
sumber
Cara termudah adalah mendefinisikan kelas, sebut saja Namespace. yang menggunakan objek dict .update () pada dict. Kemudian, dikt akan diperlakukan sebagai objek.
sumber