Saya mencoba untuk mengkonversi "data" kelas gondrong gondrong menjadi tuple bernama. Kelas saya saat ini terlihat seperti ini:
class Node(object):
def __init__(self, val, left=None, right=None):
self.val = val
self.left = left
self.right = right
Setelah konversi menjadi namedtuple
seperti:
from collections import namedtuple
Node = namedtuple('Node', 'val left right')
Tapi ada masalah di sini. Kelas asli saya memungkinkan saya untuk memberikan nilai dan menjaga standar dengan menggunakan nilai default untuk argumen nama / kata kunci. Sesuatu seperti:
class BinaryTree(object):
def __init__(self, val):
self.root = Node(val)
Tapi ini tidak berfungsi dalam kasus tuple bernama refactored saya karena mengharapkan saya untuk lulus semua bidang. Tentu saja saya bisa menggantikan kejadian Node(val)
untuk Node(val, None, None)
tetapi tidak sesuai dengan keinginan saya.
Jadi apakah ada trik bagus yang dapat membuat penulisan ulang saya berhasil tanpa menambahkan banyak kerumitan kode (metaprogramming) atau haruskah saya menelan pil dan melanjutkan dengan "pencarian dan ganti"? :)
Node
kelas orisinal Anda apa adanya. Mengapa mengonversi ke nama tuple?Node
dan lainnya adalah objek nilai pemegang data sederhana dengan sekelompok bidang yang berbeda (Node
hanya salah satunya). Deklarasi kelas ini tidak lebih dari garis noise IMHO karena itu ingin memangkasnya. Mengapa mempertahankan sesuatu yang tidak diperlukan? :).debug_print()
metode berjalan di pohon dan mencetaknya?BinaryTree
kelas.Node
dan pemegang data lainnya tidak memerlukan metode khusus seperti itu mengingat tupel yang diberi nama memiliki representasi yang layak__str__
dan__repr__
memadai. :)Jawaban:
Python 3.7
Gunakan parameter default .
Atau lebih baik lagi, gunakan perpustakaan kacamata baru , yang jauh lebih bagus daripada namedtuple.
Sebelum Python 3.7
Setel
Node.__new__.__defaults__
ke nilai default.Sebelum Python 2.6
Setel
Node.__new__.func_defaults
ke nilai default.Memesan
Di semua versi Python, jika Anda menetapkan lebih sedikit nilai default daripada yang ada di namesuple, default diterapkan ke parameter paling kanan. Ini memungkinkan Anda menyimpan beberapa argumen seperti argumen yang diperlukan.
Wrapper untuk Python 2.6 hingga 3.6
Inilah pembungkus untuk Anda, yang bahkan memungkinkan Anda (secara opsional) mengatur nilai default ke sesuatu selain
None
. Ini tidak mendukung argumen yang diperlukan.Contoh:
sumber
isinstance
... semua pro, tidak ada kontra ... sayang sekali Anda sedikit terlambat untuk pesta. Ini jawaban terbaik.(None)
bukan tuple, iniNone
. Jika Anda menggunakannya(None,)
, itu akan berfungsi dengan baik.Node.__new__.__defaults__= (None,) * len(Node._fields)
Saya subclassed namedtuple dan mengalahkan
__new__
metode:Ini mempertahankan hierarki tipe intuitif, yang penciptaan fungsi pabrik tidak menyamar sebagai kelas.
sumber
__new__
tidak dipanggil saat_replace
digunakan.Bungkus dalam suatu fungsi.
sumber
isinstance(Node('val'), Node)
: sekarang akan meningkatkan pengecualian, daripada mengembalikan True. Meskipun sedikit lebih bertele-tele, jawaban @ justinfay (di bawah) mempertahankan informasi hierarki jenis dengan benar, jadi mungkin pendekatan yang lebih baik jika orang lain akan berinteraksi dengan instance Node.def make_node(...):
daripada berpura-pura sebagai definisi kelas. Dengan cara itu pengguna tidak tergoda untuk memeriksa tipe polimorfisme pada fungsi tetapi menggunakan definisi tuple itu sendiri.isinstance
salah menggunakan .Dengan
typing.NamedTuple
di Python 3.6.1+ Anda bisa memberikan nilai default dan anotasi tipe ke bidang NamedTuple. Gunakantyping.Any
jika Anda hanya membutuhkan yang pertama:Pemakaian:
Juga, jika Anda memerlukan nilai default dan mutabilitas opsional, Python 3.7 akan memiliki kelas data (PEP 557) yang dapat dalam beberapa kasus (banyak?) Menggantikan namedtuple.
Sidenote: satu kekhasan dari spesifikasi anotasi saat ini (ekspresi setelah
:
untuk parameter dan variabel dan setelah->
untuk fungsi) dengan Python adalah bahwa mereka dievaluasi pada waktu definisi * . Jadi, karena "nama-nama kelas menjadi didefinisikan setelah seluruh badan kelas telah dieksekusi", penjelasan untuk'Node'
dalam bidang kelas di atas harus berupa string untuk menghindari NameError.Jenis petunjuk ini disebut "referensi maju" ( [1] , [2] ), dan dengan PEP 563 Python 3.7+ akan memiliki
__future__
impor (akan diaktifkan secara default di 4.0) yang akan memungkinkan untuk menggunakan referensi maju tanpa kutipan, menunda evaluasi mereka.* AFAICT hanya anotasi variabel lokal yang tidak dievaluasi saat runtime. (sumber: PEP 526 )
sumber
left
danright
(yaituNode
) adalah tipe yang sama dengan kelas yang didefinisikan dan karenanya harus ditulis sebagai string.my_list: List[T] = None
self.my_list = my_list if my_list is not None else []
? Tidak bisakah kita menggunakan parameter default seperti ini?typing.NamedTuple
. Tetapi dengan kelas data Anda dapat menggunakanField
objek dengandefault_factory
attr. untuk ini, ganti idiom Anda denganmy_list: List[T] = field(default_factory=list)
.Ini adalah contoh langsung dari dokumen :
Jadi, contoh OP adalah:
Namun, saya suka beberapa jawaban lain yang diberikan di sini lebih baik. Saya hanya ingin menambahkan ini untuk kelengkapan.
sumber
_
metode (yang pada dasarnya berarti metode pribadi) untuk sesuatureplace
yang sepertinya cukup berguna ..*args
. Mungkin saja itu ditambahkan ke bahasa sebelum banyak dari hal-hal itu distandarisasi._
prefix adalah untuk menghindari bertabrakan dengan nama-nama bidang tuple ditetapkan pengguna (kutipan doc relevan: "Setiap berlaku Python identifier dapat digunakan untuk fieldname kecuali untuk nama dimulai dengan garis bawah."). Adapun string yang dipisahkan ruang, saya pikir itu hanya untuk menyimpan beberapa penekanan tombol (dan Anda dapat melewati urutan string jika Anda mau)._
masuk akal.Saya tidak yakin apakah ada cara mudah hanya dengan namesuple bawaan. Ada modul bagus bernama recordtype yang memiliki fungsi ini:
sumber
recordtype
tentu terlihat menarik untuk pekerjaan di masa depan. +1recordtype
bisa berubah sedangkannamedtuple
tidak. Ini mungkin penting jika Anda ingin objek menjadi hashable (yang saya kira Anda tidak, karena dimulai sebagai kelas).Ini adalah versi yang lebih ringkas yang terinspirasi oleh jawaban justinfay:
sumber
Node(1, 2)
tidak bekerja dengan resep ini, tetapi bekerja di jawaban @ justinfay. Kalau tidak, ini cukup bagus (+1).Di python3.7 + ada default baru = argumen kata kunci.
Contoh penggunaan:
sumber
Singkat, sederhana, dan tidak membuat orang menggunakan dengan
isinstance
tidak tepat:sumber
Contoh yang sedikit diperluas untuk menginisialisasi semua argumen yang hilang dengan
None
:sumber
Python 3.7: pengenalan
defaults
param dalam namedtuple definition.Contoh seperti yang ditunjukkan dalam dokumentasi:
Baca lebih lanjut di sini .
sumber
Anda juga dapat menggunakan ini:
Ini pada dasarnya memberi Anda kemungkinan untuk membuat tuple bernama apa pun dengan nilai default dan mengabaikan hanya parameter yang Anda butuhkan, misalnya:
sumber
Menggabungkan pendekatan @Denis dan @Mark:
Itu harus mendukung pembuatan tuple dengan argumen posisi dan juga dengan kasus campuran. Kasus uji:
tetapi juga mendukung TypeError:
sumber
Saya menemukan versi ini lebih mudah dibaca:
Ini tidak seefisien karena membutuhkan penciptaan objek dua kali tetapi Anda bisa mengubahnya dengan mendefinisikan duple default di dalam modul dan hanya memiliki fungsi melakukan ganti baris.
sumber
Karena Anda menggunakan
namedtuple
sebagai kelas data, Anda harus menyadari bahwa python 3.7 akan memperkenalkan a@dataclass
dekorator untuk tujuan ini - dan tentu saja ia memiliki nilai default.Contoh dari dokumen :
Jauh lebih bersih, mudah dibaca dan dapat digunakan daripada meretas
namedtuple
. Tidak sulit untuk memprediksi bahwa penggunaannamedtuple
s akan turun dengan adopsi 3,7.sumber
Terinspirasi oleh jawaban ini untuk pertanyaan yang berbeda, berikut ini adalah solusi yang saya usulkan berdasarkan metaclass dan penggunaannya
super
(untuk menangani pengaliran di masa depan dengan benar). Ini sangat mirip dengan jawaban justinfay .Kemudian:
sumber
Jawaban oleh jterrace untuk menggunakan recordtype sangat bagus, tetapi penulis perpustakaan merekomendasikan untuk menggunakan proyek daftar namanya , yang menyediakan implementasi yang bisa berubah (
namedlist
) dan tidak berubah (namedtuple
).sumber
Inilah jawaban umum singkat dan sederhana dengan sintaks yang bagus untuk tuple bernama dengan argumen default:
Pemakaian:
Diperkecil:
sumber
Menggunakan
NamedTuple
kelas dariAdvanced Enum (aenum)
perpustakaan saya , dan menggunakanclass
sintaks, ini cukup sederhana:Satu kelemahan potensial adalah persyaratan untuk
__doc__
string untuk atribut apa pun dengan nilai default (itu opsional untuk atribut sederhana). Dalam penggunaannya terlihat seperti:Kelebihan ini lebih dari
justinfay's answer
:adalah kesederhanaan, serta
metaclass
berbasis bukanexec
berbasis.sumber
Solusi lain:
Pemakaian:
sumber
Berikut ini versi pembungkus Mark Lodato yang kurang fleksibel, tetapi lebih ringkas: Dibutuhkan bidang dan default sebagai kamus.
Contoh:
sumber
dict
tidak memiliki jaminan pemesanan.