Apakah ada cara untuk dengan mudah mendefinisikan struktur mirip-C dalam Python? Saya lelah menulis hal-hal seperti:
class MyStruct():
def __init__(self, field1, field2, field3):
self.field1 = field1
self.field2 = field2
self.field3 = field3
MyStruct = namedtuple("MyStruct", "field1 field2 field3")
pandas.Series(a=42).a
harus melakukannya jika Anda seorang ilmuwan data ...Jawaban:
Gunakan tuple bernama , yang ditambahkan ke modul koleksi di perpustakaan standar di Python 2.6. Anda juga dapat menggunakan resep tuple bernama Raymond Hettinger jika Anda perlu mendukung Python 2.4.
Ini bagus untuk contoh dasar Anda, tetapi juga mencakup banyak kasus tepi yang mungkin Anda temui nanti. Fragmen Anda di atas akan ditulis sebagai:
Jenis yang baru dibuat dapat digunakan seperti ini:
Anda juga dapat menggunakan argumen bernama:
sumber
Pembaruan : Kelas Data
Dengan diperkenalkannya Kelas Data di Python 3.7 kami menjadi sangat dekat.
Contoh berikut mirip dengan contoh NamedTuple di bawah ini, tetapi objek yang dihasilkan bisa berubah dan memungkinkan untuk nilai-nilai default.
Ini berfungsi baik dengan modul pengetikan baru jika Anda ingin menggunakan anotasi jenis yang lebih spesifik.
Saya sudah menunggu dengan putus asa untuk ini! Jika Anda bertanya kepada saya, Kelas Data dan deklarasi NamedTuple baru , dikombinasikan dengan modul pengetikan adalah anugerah!
Deklarasi NamedTuple yang ditingkatkan
Sejak Python 3.6 itu menjadi sangat sederhana dan indah (IMHO), selama Anda dapat hidup dengan kekekalan .
Cara baru untuk mendeklarasikan NamedTuples diperkenalkan, yang memungkinkan anotasi jenis juga:
sumber
dataclass
modul baru di Python 3.7, tetapi Anda bisapip install dataclasses
. Ini adalah backport di Python 3.6. pypi.org/project/dataclasses/#description@dataclass
ada di sini: pypi.org/project/dataclasses/#descriptionAnda dapat menggunakan tuple untuk banyak hal di mana Anda akan menggunakan struct di C (misalnya x, y koordinat atau warna RGB misalnya).
Untuk yang lainnya, Anda dapat menggunakan kamus, atau kelas utilitas seperti ini :
Saya pikir diskusi "pasti" ada di sini , dalam versi yang diterbitkan dari Python Cookbook.
sumber
TypeError: this constructor takes no arguments
Mungkin Anda mencari Structs tanpa konstruktor:
sumber
class Sample:
tidak segera melakukan apa pun; mereka mengatur atribut kelas. Itu selalu dapat diakses seperti misalnyaSample.name
.s1
dans2
saat runtime. Kecuali jika tidak dilarang, Anda dapat menambah atau mengubahname
atribut pada instance kelas apa pun kapan saja, baik kelas tersebut memilikiname
atribut atau tidak . Mungkin masalah fungsional terbesar dengan melakukan ini adalah bahwa instance berbeda dari kelas yang sama akan berperilaku berbeda tergantung pada apakah Anda telah menetapkanname
. Jika Anda memperbaruiSample.name
, objek apa pun tanpaname
properti yang ditetapkan secara eksplisit akan mengembalikan yang baruname
.self
kata kunci dan garis konstruktor jika Anda bertanya kepada saya. Saya akan menghargai jika Jose dapat mengedit jawabannya untuk menambahkan pesan peringatan tentang risiko berbagi nilai secara tidak sengaja di seluruh instance.Bagaimana dengan kamus?
Sesuatu seperti ini:
Kemudian Anda bisa menggunakan ini untuk memanipulasi nilai:
Dan nilainya tidak harus berupa string. Mereka bisa menjadi hampir semua objek lain.
sumber
pt3.w = 1 print pt3.w
Dalam bahasa dengan dikt, lebih baik menggunakannya, terutama untuk objek yang serial, karena Anda dapat secara otomatis menggunakan impor json untuk menyimpannya dan perpustakaan serialisasi lainnya selama Anda tidak memiliki yang aneh barang-barang di dalam dikt Anda. Diktik adalah solusi untuk menjaga data dan logika terpisah dan lebih baik daripada struct untuk orang-orang yang tidak ingin menulis serialisasi kustom dan fungsi unserialize dan tidak ingin menggunakan serializers non-portabel seperti acar.Anda dapat mengakses bidang kelas menggunakan kamus karena bidang kelas, metode, dan semua propertinya disimpan secara internal menggunakan dicts (setidaknya dalam CPython).
... Yang mengarahkan kami ke komentar kedua Anda. Percaya bahwa perintah Python "berat" adalah konsep yang sangat non-pythonistik. Dan membaca komentar seperti itu membunuh Python Zen saya. Itu tidak baik.
Anda tahu, ketika Anda mendeklarasikan kelas Anda sebenarnya membuat pembungkus yang cukup rumit di sekitar kamus - jadi, jika ada, Anda menambahkan lebih banyak overhead daripada menggunakan kamus sederhana. Bagaimanapun juga, overhead yang tidak ada artinya. Jika Anda bekerja pada aplikasi kritis kinerja, gunakan C atau sesuatu.
sumber
self['member']
lebih dari 3 karakterself.member
, dan semua karakter tersebut relatif tidak ramah pergelangan tangan.Anda bisa subkelas struktur C yang tersedia di perpustakaan standar. The ctypes modul menyediakan kelas Struktur . Contoh dari dokumen:
sumber
Saya juga ingin menambahkan solusi yang menggunakan slot :
Jelas memeriksa dokumentasi untuk slot tetapi penjelasan cepat slot adalah bahwa itu adalah cara python mengatakan: "Jika Anda dapat mengunci atribut ini dan hanya atribut ini ke dalam kelas sehingga Anda berkomitmen bahwa Anda tidak akan menambahkan atribut baru setelah kelas instantiated (ya Anda dapat menambahkan atribut baru ke instance kelas, lihat contoh di bawah) maka saya akan menghapus alokasi memori besar yang memungkinkan untuk menambahkan atribut baru ke instance kelas dan menggunakan apa yang saya butuhkan untuk atribut slotted ini ".
Contoh menambahkan atribut ke instance kelas (sehingga tidak menggunakan slot):
Output: 8
Contoh mencoba menambahkan atribut ke instance kelas di mana slot digunakan:
Output: AttributeError: objek 'Point' tidak memiliki atribut 'z'
Ini secara efektif dapat berfungsi sebagai struct dan menggunakan memori lebih sedikit daripada kelas (seperti struct akan, meskipun saya belum meneliti persis berapa banyak). Disarankan untuk menggunakan slot jika Anda akan membuat banyak instance objek dan tidak perlu menambahkan atribut. Objek titik adalah contoh yang baik dari ini karena ada kemungkinan bahwa orang dapat instantiate banyak poin untuk menggambarkan dataset.
sumber
Anda juga dapat meneruskan parameter init ke variabel instan dengan posisi
sumber
Point3dStruct
deklarasi,Point3dStruct(5, 6)
tidak akan berfungsi seperti yang diharapkan. Sungguh aneh bahwa tidak ada yang menulis ini dalam semua 6 tahun.print
>print()
, danattrs[n]
>next(attrs)
(filter sekarang adalah objek yang dapat diulang sendiri dan membutuhkannext
).Setiap kali saya membutuhkan "objek data instan yang juga berperilaku seperti kamus" (Saya tidak memikirkan C struct!), Saya memikirkan hack lucu ini:
Sekarang Anda bisa mengatakan:
Sangat berguna untuk saat-saat ketika Anda membutuhkan "tas data yang BUKAN kelas", dan untuk saat namatuple tidak dapat dipahami ...
sumber
Anda mengakses struct C-Style dalam python dengan cara berikut.
jika Anda hanya ingin menggunakan objek cuct
jika Anda ingin membuat array objek cstruct
Catatan: alih-alih nama 'cstruct', harap gunakan nama struct Anda alih-alih var_i, var_f, var_str, harap tentukan variabel anggota struktur Anda.
sumber
Beberapa jawaban di sini sangat rumit. Opsi paling sederhana yang saya temukan adalah (dari: http://norvig.com/python-iaq.html ):
Inisialisasi:
menambahkan lebih banyak:
sunting: Maaf tidak melihat contoh ini lebih jauh ke bawah.
sumber
Ini mungkin agak terlambat tapi saya membuat solusi menggunakan Python Meta-Classes (versi dekorator di bawah ini juga).
Ketika
__init__
dipanggil pada saat run time, ia mengambil setiap argumen dan nilainya dan menetapkannya sebagai variabel instan ke kelas Anda. Dengan cara ini Anda bisa membuat kelas struct-like tanpa harus menetapkan setiap nilai secara manual.Contoh saya tidak memiliki pengecekan kesalahan sehingga lebih mudah diikuti.
Ini dia beraksi.
Saya diposting di reddit dan / u / matchu memposting versi dekorator yang lebih bersih. Saya mendorong Anda untuk menggunakannya kecuali jika Anda ingin memperluas versi metaclass.
sumber
Saya menulis dekorator yang dapat Anda gunakan pada metode apa saja untuk membuatnya sehingga semua argumen yang diteruskan, atau default apa pun, ditetapkan ke instance.
Peragaan cepat. Perhatikan bahwa saya menggunakan argumen posisi
a
, gunakan nilai default untukb
, dan argumen bernamac
. Saya kemudian mencetak semua 3 referensiself
, untuk menunjukkan bahwa mereka telah ditugaskan dengan benar sebelum metode dimasukkan.Perhatikan bahwa dekorator saya harus bekerja dengan metode apa pun, bukan hanya
__init__
.sumber
Saya tidak melihat jawaban ini di sini, jadi saya pikir saya akan menambahkannya karena saya condong ke Python sekarang dan baru saja menemukannya. The Python tutorial (Python 2 dalam hal ini) memberikan sederhana berikut dan contoh yang efektif:
Yaitu, objek kelas kosong dibuat, kemudian dipakai, dan bidang ditambahkan secara dinamis.
Sisi baiknya adalah ini sangat sederhana. Kelemahannya adalah tidak mendokumentasikan diri sendiri (anggota yang dituju tidak terdaftar di manapun di "definisi" kelas), dan bidang yang tidak disetel dapat menyebabkan masalah saat diakses. Kedua masalah tersebut dapat diselesaikan dengan:
Sekarang sekilas Anda setidaknya bisa melihat bidang apa yang akan Anda harapkan dari program ini.
Keduanya rentan terhadap kesalahan ketik,
john.slarly = 1000
akan berhasil. Tetap saja berhasil.sumber
Berikut ini adalah solusi yang menggunakan kelas (tidak pernah dipakai) untuk menyimpan data. Saya suka bahwa cara ini melibatkan sangat sedikit pengetikan dan tidak memerlukan paket tambahan dll.
Anda dapat menambahkan lebih banyak bidang nanti, sesuai kebutuhan:
Untuk mendapatkan nilai, bidang diakses seperti biasa:
sumber
Secara pribadi, saya suka varian ini juga. Itu memperluas jawaban @ dF .
Ini mendukung dua mode inisialisasi (yang dapat dicampur):
Juga, ini mencetak lebih baik:
sumber
Solusi untuk struct berikut ini diilhami oleh implementasi namesuple dan beberapa jawaban sebelumnya. Namun, tidak seperti nametuple itu bisa berubah, dalam nilai-nilai itu, tetapi seperti struct c-style yang tidak dapat diubah dalam nama / atribut, yang bukan kelas atau dikt normal.
Pemakaian:
sumber
Ada paket python persis untuk tujuan ini. lihat cstruct2py
cstruct2py
adalah pustaka python murni untuk menghasilkan kelas python dari kode C dan menggunakannya untuk mengemas dan membongkar data. Perpustakaan dapat mengurai C headres (struct, unions, enums, dan deklarasi array) dan meniru mereka dengan python. Kelas pythonic yang dihasilkan dapat menguraikan dan mengemas data.Sebagai contoh:
Pertama kita perlu membuat struct pythonic:
Sekarang kita dapat mengimpor semua nama dari kode C:
Kami juga dapat melakukannya secara langsung:
Menggunakan tipe dan definisi dari kode C.
Outputnya adalah:
Untuk
cstruct2py
menjalankan klon :sumber
Saya pikir kamus struktur Python cocok untuk persyaratan ini.
sumber
https://stackoverflow.com/a/32448434/159695 tidak berfungsi di Python3.
https://stackoverflow.com/a/35993/159695 berfungsi di Python3.
Dan saya memperluasnya untuk menambahkan nilai default.
sumber
Jika Anda tidak memiliki 3,7 untuk @dataclass dan perlu mutabilitas, kode berikut ini mungkin cocok untuk Anda. Ini cukup mendokumentasikan diri sendiri dan ramah-IDE (auto-complete), mencegah penulisan dua kali, mudah diperpanjang dan sangat mudah untuk menguji bahwa semua variabel instan sepenuhnya diinisialisasi:
sumber
Ini trik cepat dan kotor:
Bagaimana cara kerjanya? Itu hanya menggunakan kembali kelas builtin
Warning
(berasal dariException
) dan menggunakannya karena Anda sendiri kelas yang ditentukan.Poin baiknya adalah Anda tidak perlu mengimpor atau mendefinisikan apa pun terlebih dahulu, bahwa "Peringatan" adalah nama pendek, dan itu juga menjelaskan bahwa Anda melakukan sesuatu yang kotor yang tidak boleh digunakan di tempat lain selain naskah kecil Anda.
Ngomong-ngomong, saya mencoba menemukan sesuatu yang lebih sederhana seperti
ms = object()
tetapi tidak bisa (contoh terakhir ini tidak berfungsi). Jika Anda memilikinya, saya tertarik.sumber
Cara terbaik yang saya temukan untuk melakukan ini adalah dengan menggunakan kelas kamus khusus seperti yang dijelaskan dalam posting ini: https://stackoverflow.com/a/14620633/8484485
Jika dukungan pelengkapan otomatis iPython diperlukan, cukup tentukan fungsi dir () seperti ini:
Anda kemudian mendefinisikan struct semu Anda seperti: (ini bersarang)
Anda kemudian dapat mengakses nilai-nilai di dalam my_struct seperti ini:
print(my_struct.com1.inst)
=>
[5]
sumber
NamedTuple nyaman. tetapi tidak ada yang berbagi kinerja dan penyimpanan.
Jika Anda
__dict__
tidak menggunakan, silakan pilih antara__slots__
(kinerja dan penyimpanan lebih tinggi) danNamedTuple
(jelas untuk membaca dan menggunakan)Anda dapat meninjau tautan ini ( Penggunaan slot ) untuk mendapatkan
__slots__
informasi lebih lanjut.sumber