Saya punya pertanyaan tentang idiom dan keterbacaan, dan tampaknya ada benturan filosofi Python untuk kasus khusus ini:
Saya ingin membangun kamus A dari kamus B. Jika kunci tertentu tidak ada di B, maka jangan lakukan apa-apa dan lanjutkan.
Cara mana yang lebih baik?
try:
A["blah"] = B["blah"]
except KeyError:
pass
atau
if "blah" in B:
A["blah"] = B["blah"]
"Lakukan dan minta maaf" vs. "kesederhanaan dan kesederhanaan".
Mana yang lebih baik dan mengapa?
python
idioms
readability
defaultdict
code-readability
LeeMobile
sumber
sumber
if "blah" in B.keys()
, atauif B.has_key("blah")
.A.update(B)
tidak bekerja untuk Anda?has_key
tidak digunakan lagiin
dan memeriksaB.keys()
perubahan operasi O (1) menjadi O (n)..has_key
tidak digunakan lagi dankeys
membuat daftar yang tidak dibutuhkan di py2k, dan berlebihan di py3kA = dict((k, v) for (k, v) in B if we_want_to_include(k))
.Jawaban:
Pengecualian tidak bersyarat.
Versi bersyarat lebih jelas. Itu wajar: ini adalah kontrol aliran langsung, yang dirancang untuk kondisional, bukan pengecualian.
Versi pengecualian terutama digunakan sebagai pengoptimalan saat melakukan pencarian ini dalam satu putaran: untuk beberapa algoritme, versi ini memungkinkan penghapusan pengujian dari loop dalam. Tidak ada manfaat itu di sini. Ini memiliki keuntungan kecil yang menghindari keharusan mengatakan
"blah"
dua kali, tetapi jika Anda melakukan banyak hal ini Anda mungkin harus memilikimove_key
fungsi pembantu .Secara umum, saya sangat menyarankan untuk tetap menggunakan versi bersyarat secara default kecuali Anda memiliki alasan khusus untuk tidak melakukannya. Kondisional adalah cara yang jelas untuk melakukan ini, yang biasanya merupakan rekomendasi kuat untuk memilih satu solusi daripada yang lain.
sumber
"blah"
lebih sering, yang mengarah ke situasi yang lebih rawan kesalahan.Ada juga cara ketiga untuk menghindari pengecualian dan pencarian ganda, yang dapat menjadi penting jika pencarian mahal:
value = B.get("blah", None) if value is not None: A["blah"] = value
Jika Anda mengharapkan kamus berisi
None
nilai, Anda dapat menggunakan beberapa konstanta esoterik sepertiNotImplemented
,Ellipsis
atau membuat yang baru:MyConst = object() def update_key(A, B, key): value = B.get(key, MyConst) if value is not MyConst: A[key] = value
Bagaimanapun, menggunakan
update()
adalah opsi yang paling mudah dibaca bagi saya:a.update((k, b[k]) for k in ("foo", "bar", "blah") if k in b)
sumber
Dari apa yang saya pahami, Anda ingin memperbarui dict A dengan kunci, pasangan nilai dari dict B
update
adalah pilihan yang lebih baik.Contoh:
>>> A = {'a':1, 'b': 2, 'c':3} >>> B = {'d': 2, 'b':5, 'c': 4} >>> A.update(B) >>> A {'a': 1, 'c': 4, 'b': 5, 'd': 2} >>>
sumber
A.update({k: v for k, v in B.iteritems() if k in specificset})
Kutipan langsung dari wiki kinerja Python:
Jadi tampaknya kedua opsi tersebut dapat dijalankan tergantung dari situasi. Untuk lebih jelasnya Anda mungkin ingin memeriksa tautan ini: Coba-kecuali-kinerja
sumber
Saya pikir aturan umum di sini adalah
A["blah"]
biasanya akan ada, jika demikian coba-kecuali bagus jika tidak maka gunakanif "blah" in b:
Saya pikir "mencoba" itu murah pada waktunya tetapi "kecuali" lebih mahal.
sumber
Saya pikir contoh kedua adalah apa yang harus Anda lakukan kecuali kode ini masuk akal:
try: A["foo"] = B["foo"] A["bar"] = B["bar"] A["baz"] = B["baz"] except KeyError: pass
Ingatlah bahwa kode akan dibatalkan segera setelah ada kunci yang tidak ada di dalamnya
B
. Jika kode ini masuk akal, maka Anda harus menggunakan metode pengecualian, jika tidak gunakan metode pengujian. Menurut pendapat saya, karena lebih pendek dan dengan jelas mengungkapkan maksudnya, jauh lebih mudah dibaca daripada metode pengecualian.Tentu saja, orang yang menyuruh Anda menggunakan
update
itu benar. Jika Anda menggunakan versi Python yang mendukung pemahaman kamus, saya sangat menyukai kode ini:updateset = {'foo', 'bar', 'baz'} A.update({k: B[k] for k in updateset if k in B})
sumber
for key in ["foo", "bar", "baz"]: try: A[key] = B[key]
Aturan dalam bahasa lain adalah mencadangkan pengecualian untuk kondisi luar biasa, yaitu kesalahan yang tidak terjadi dalam penggunaan biasa. Tidak tahu bagaimana aturan itu berlaku untuk Python, karena StopIteration seharusnya tidak ada pada aturan itu.
sumber
Secara pribadi, saya condong ke metode kedua (tetapi menggunakan
has_key
):if B.has_key("blah"): A["blah"] = B["blah"]
Dengan begitu, setiap operasi penugasan hanya dua baris (bukan 4 dengan coba / kecuali), dan pengecualian apa pun yang terlempar akan menjadi kesalahan nyata atau hal-hal yang Anda lewatkan (bukan hanya mencoba mengakses kunci yang tidak ada) .
Ternyata (lihat komentar pada pertanyaan Anda),
has_key
sudah usang - jadi saya rasa lebih baik ditulis sebagaiif "blah" in B: A["blah"] = B["blah"]
sumber
Memulai
Python 3.8
, dan pengenalan ekspresi penugasan (PEP 572) (:=
operator), kita dapat menangkap nilai kondisidictB.get('hello', None)
dalam variabelvalue
untuk memeriksa apakah tidakNone
(sebagaidict.get('hello', None)
mengembalikan nilai terkait atauNone
) dan kemudian menggunakannya di dalam tubuh variabel. kondisi:# dictB = {'hello': 5, 'world': 42} # dictA = {} if value := dictB.get('hello', None): dictA["hello"] = value # dictA is now {'hello': 5}
sumber
Meskipun jawaban yang diterima menekankan pada prinsip "lihat sebelum Anda melompat" mungkin berlaku untuk sebagian besar bahasa, lebih banyak pythonic mungkin merupakan pendekatan pertama, berdasarkan prinsip python. Belum lagi itu adalah gaya pengkodean yang sah di python. Hal yang penting adalah memastikan Anda menggunakan blok coba kecuali dalam konteks yang benar dan mengikuti praktik terbaik. Misalnya. melakukan terlalu banyak hal dalam blok percobaan, menangkap pengecualian yang sangat luas, atau lebih buruk lagi - klausa kosong kecuali dll.
Lihat referensi dokumen python di sini .
Juga, blog ini dari Brett ini, salah satu pengembang inti, membahas sebagian besar secara singkat.
Lihat diskusi SO lainnya di sini :
sumber