
Hai, habrozhiteli! Mempelajari semua kemungkinan Python adalah tugas yang sulit, dan dengan buku ini Anda dapat fokus pada keterampilan praktis yang sangat penting. Gali emas tersembunyi di pustaka standar Python dan mulailah menulis kode bersih hari ini.
Jika Anda memiliki pengalaman dengan versi Python yang lebih lama, Anda bisa mempercepat pekerjaan dengan templat dan fungsi modern yang diperkenalkan di Python 3.
Jika Anda telah bekerja dengan bahasa pemrograman lain dan ingin beralih ke Python, Anda akan menemukan tips praktis yang diperlukan untuk menjadi pythonist yang efektif.
Jika Anda ingin belajar cara menulis kode bersih, Anda akan menemukan contoh paling menarik di sini dan trik yang kurang dikenal.
Kutipan "Ekspresi Kamus Paling Gila di Barat"
Kadang-kadang Anda menemukan contoh kecil kode yang memiliki kedalaman yang benar-benar tak terduga - satu baris kode yang dapat banyak mengajarkan Anda jika Anda memikirkannya dengan cermat. Sepotong kode seperti koan dalam Buddhisme Zen: pertanyaan atau pernyataan yang digunakan dalam praktik Zen untuk menimbulkan keraguan dan menguji prestasi siswa.
Sepotong kecil kode yang kita bahas di bagian ini adalah salah satu contohnya. Pada pandangan pertama, ini mungkin terlihat seperti ekspresi kosakata langsung, tetapi setelah pemeriksaan lebih dekat mengirimkan Anda pada pelayaran psychedelic yang memperluas pikiran dengan penerjemah Python.
Saya mendapatkan buzz dari one-liner ini yang bahkan pernah saya cetak di lencana peserta konferensi Python saya sebagai alasan untuk percakapan. Ini menyebabkan beberapa dialog konstruktif dengan anggota buletin email Python saya.
Jadi, tanpa basa-basi lagi, inilah potongan kode ini. Beristirahat sejenak untuk merenungkan ekspresi kosakata di bawah ini dan apa yang harus diakibatkan oleh perhitungannya:
>>> {True: '', 1: '', 1.0: ''}
Saya akan menunggu di sini ...
Oke siap
Berikut ini adalah hasil yang kami dapatkan ketika mengevaluasi ekspresi kamus di atas dalam sesi juru bahasa Python:
>>> {True: '', 1: '', 1.0: ''} {True: ''}
Saya akui, ketika saya melihat hasil ini untuk pertama kalinya, saya sangat tercengang. Tapi semuanya akan jatuh ke tempatnya ketika Anda melakukan studi langkah demi langkah santai tentang apa yang terjadi di sini. Mari kita renungkan mengapa kita mendapatkan ini, harus saya katakan, bukan hasil yang sangat intuitif.
Saat Python memproses ekspresi kamus kami, pertama-tama ia membangun objek kamus kosong yang baru, dan kemudian memberikan kunci dan nilai-nilai padanya dalam urutan yang dilewatkan ke ekspresi kamus.
Kemudian, ketika kami menguraikannya menjadi beberapa bagian, ekspresi kamus kami akan setara dengan urutan instruksi berikut yang dijalankan secara berurutan:
>>> xs = dict() >>> xs[True] = '' >>> xs[1] = '' >>> xs[1.0] = ''
Anehnya, Python menganggap semua kunci yang digunakan dalam kamus ini setara dengan:
>>> True == 1 == 1.0 True
Oke, tapi tunggu sebentar. Saya yakin Anda secara intuitif dapat mengakui bahwa 1,0 == 1, tetapi mengapa True dianggap juga setara dengan 1? Pertama kali saya melihat ungkapan kamus ini, itu benar-benar membingungkan saya.
Mengaduk-aduk sedikit dalam dokumentasi Python, saya menemukan bahwa Python memperlakukan tipe bool sebagai subkelas dari tipe int. Ini adalah kasus dalam Python 2 dan Python 3:
Tipe boolean adalah subtipe dari tipe integer, dan nilai boolean berperilaku, masing-masing, sebagai nilai 0 dan 1 di hampir semua konteks, dengan pengecualian bahwa ketika dikonversi ke tipe string, nilai string 'False' atau 'True dikembalikan, masing-masing '
Dan tentu saja, ini berarti bahwa dalam Python, nilai Boolean secara teknis dapat digunakan sebagai daftar atau indeks tuple:
>>> ['', ''][True] ''
Tetapi Anda mungkin tidak boleh menggunakan variabel logis semacam ini atas nama kejelasan (dan kesehatan mental kolega Anda).
Dengan satu atau lain cara, kembali ke ekspresi kamus kami.
Adapun bahasa Python, semua nilai ini - Benar, 1, dan 1.0 - mewakili kunci kamus yang sama. Ketika penerjemah mengevaluasi ekspresi kamus, itu berulang kali menimpa nilai kunci Sejati. Ini menjelaskan mengapa di bagian paling akhir kamus yang dihasilkan hanya berisi satu kunci.
Sebelum kita melangkah lebih jauh, lihat kembali ekspresi kamus asli:
>>> {True: '', 1: '', 1.0: ''} {True: ''}
Mengapa kita masih mendapatkan True sebagai kuncinya di sini? Bukankah kuncinya juga berubah menjadi 1.0 karena penugasan berulang di akhir?
Setelah sedikit riset dalam kode sumber interpreter Python, saya menemukan bahwa ketika nilai baru dikaitkan dengan objek kunci, kamus Python sendiri tidak memperbarui objek kunci ini:
>>> ys = {1.0: ''} >>> ys[True] = '' >>> ys {1.0: ''}
Tentu saja, ini masuk akal sebagai optimasi kinerja: jika kunci dianggap identik, lalu mengapa membuang waktu memperbarui yang asli?
Dalam contoh terakhir, Anda melihat bahwa objek True asli sebagai kunci tidak pernah diganti. Untuk alasan ini, representasi string dari kamus masih mencetak kunci sebagai True (bukan 1 atau 1.0).
Dengan apa yang sekarang kita ketahui, tampaknya, nilai-nilai dalam kamus yang dihasilkan ditulis ulang hanya karena perbandingan akan selalu menunjukkannya sebagai setara satu sama lain. Namun, ternyata efek ini juga bukan konsekuensi dari pengujian untuk kesetaraan dengan metode __eq__.
Kamus python bergantung pada struktur data tabel hash. Ketika saya pertama kali melihat ungkapan kamus yang luar biasa ini, pikiran pertama saya adalah bahwa perilaku semacam itu entah bagaimana terkait dengan konflik hash.
Faktanya adalah bahwa tabel hash dalam representasi internal menyimpan kunci yang tersedia di dalamnya dalam berbagai "keranjang" sesuai dengan nilai hash dari setiap kunci. Nilai hash diturunkan dari kunci sebagai nilai numerik panjang tetap yang secara unik mengidentifikasi kunci.
Fakta ini memungkinkan Anda untuk melakukan operasi pencarian cepat. Menemukan nilai hash kunci dalam tabel pencarian jauh lebih cepat daripada membandingkan objek kunci lengkap dengan semua kunci lainnya dan melakukan pemeriksaan kesetaraan.
Namun, metode untuk menghitung nilai hash umumnya tidak ideal. Dan pada akhirnya, dua atau lebih kunci yang sebenarnya berbeda akan memiliki nilai hash turunan yang sama, dan mereka akan berakhir di keranjang tabel pencarian yang sama.
Ketika dua kunci memiliki nilai hash yang sama, situasi ini disebut konflik hash dan merupakan kasus khusus dimana algoritma untuk memasukkan dan menemukan elemen dalam tabel hash harus ditangani.
Berdasarkan penilaian ini, sangat mungkin bahwa hashing entah bagaimana terkait dengan hasil yang tidak terduga yang kami peroleh dari ekspresi kamus kami. Oleh karena itu, mari kita cari tahu apakah nilai hash kunci juga memainkan peran tertentu di sini.
Saya mendefinisikan kelas di bawah ini sebagai alat detektif kecil:
class AlwaysEquals: def __eq__(self, other): return True def __hash__(self): return id(self)
Kelas ini ditandai oleh dua aspek.
Pertama, karena metode Dunder __eq__ selalu mengembalikan True, semua instance dari kelas ini berpura-pura sama dengan objek apa pun:
>>> AlwaysEquals() == AlwaysEquals() True >>> AlwaysEquals() == 42 True >>> AlwaysEquals() == '?' True
Dan kedua, setiap instance dari AlwaysEquals juga akan mengembalikan nilai hash unik yang dihasilkan oleh fungsi bawaan id ():
>>> objects = [AlwaysEquals(), AlwaysEquals(), AlwaysEquals()] >>> [hash(obj) for obj in objects] [4574298968, 4574287912, 4574287072]
Dalam Python, fungsi id () mengembalikan alamat suatu objek dalam RAM, yang dijamin unik.
Menggunakan kelas ini, Anda sekarang dapat membuat objek yang berpura-pura setara dengan objek lain, tetapi pada saat yang sama memiliki nilai hash unik yang terkait dengannya. Ini akan memungkinkan Anda untuk memeriksa apakah kunci kamus ditulis ulang, hanya mengandalkan hasil perbandingan mereka pada kesetaraan.
Dan, seperti yang Anda lihat, kunci-kunci dalam contoh berikut ini tidak sesuai, meskipun perbandingan akan selalu menunjukkan mereka setara satu sama lain:
>>> {AlwaysEquals(): '', AlwaysEquals(): ''} { <AlwaysEquals object at 0x110a3c588>: '', <AlwaysEquals object at 0x110a3cf98>: '' }
Kami juga dapat melihat ide ini dari sisi lain dan memeriksa apakah mengembalikan nilai hash yang sama adalah alasan yang cukup untuk memaksa kunci untuk ditulis ulang:
class SameHash: def __hash__(self): return 1
Membandingkan instance dari kelas SameHash akan menunjukkan mereka tidak setara satu sama lain, tetapi mereka semua akan memiliki nilai hash yang sama yaitu 1:
>>> a = SameHash() >>> b = SameHash() >>> a == b False >>> hash(a), hash(b) (1, 1)
Mari kita lihat bagaimana kamus Python merespons ketika kita mencoba menggunakan instance kelas SameHash sebagai kunci kamus:
>>> {a: 'a', b: 'b'} { <SameHash instance at 0x7f7159020cb0>: 'a', <SameHash instance at 0x7f7159020cf8>: 'b' }
Seperti contoh ini menunjukkan, efek "kunci ditimpa" disebabkan tidak hanya oleh konflik nilai hash.
Kamus melakukan pemeriksaan ekivalensi dan membandingkan nilai hash untuk menentukan apakah kedua kunci itu sama. Mari kita coba merangkum hasil penelitian kami.
Ekspresi kamus {Benar: 'ya', 1: 'tidak', 1.0: 'mungkin'} dihitung sebagai {Benar: 'mungkin'}, karena membandingkan semua kunci dari contoh ini, Benar, 1, dan 1.0, akan menunjukkan kepada mereka sebagai setara satu sama lain, dan mereka semua memiliki nilai hash yang sama:
>>> True == 1 == 1.0 True >>> (hash(True), hash(1), hash(1.0)) (1, 1, 1)
Mungkin sekarang ini tidak begitu mengejutkan bahwa kita mendapatkan hasil seperti keadaan akhir dari kamus:
>>> {True: '', 1: '', 1.0: ''} {True: ''}
Di sini kami membahas banyak topik, dan trik Python khusus ini mungkin tidak cocok di kepala pada awalnya - itu sebabnya pada awal bagian saya membandingkannya dengan koan Zen.
Jika Anda kesulitan memahami apa yang terjadi di bagian ini, cobalah bereksperimen dengan semua contoh kode dalam sesi juru bahasa Python secara bergantian. Anda akan dihargai dengan memperluas pengetahuan Anda tentang mekanisme internal bahasa Python.
»Informasi lebih lanjut tentang buku ini dapat ditemukan di
situs web penerbit»
Isi»
KutipanKupon diskon 20% untuk penjaja -
Python