


Cara Pengoptimuman Perbandingan Menjadikan Pengisihan Python Lebih Cepat
Dalam teks ini istilah Python dan CPython, yang merupakan pelaksanaan rujukan bahasa, digunakan secara bergantian. Artikel ini secara khusus menangani CPython dan tidak melibatkan pelaksanaan Python yang lain.
Python ialah bahasa yang indah yang membolehkan pengaturcara meluahkan idea mereka dalam istilah mudah meninggalkan kerumitan pelaksanaan sebenar di belakang tabir.
Salah satu perkara yang diabsahkan ialah mengisih.
Anda boleh mencari jawapan kepada soalan "bagaimana cara pengisihan dilaksanakan dalam Python?" yang hampir selalu menjawab soalan lain: "Algoritma pengisihan apakah yang digunakan oleh Python?".
Walau bagaimanapun, ini sering meninggalkan beberapa butiran pelaksanaan yang menarik.
Terdapat satu perincian pelaksanaan yang saya rasa tidak cukup dibincangkan, walaupun ia telah diperkenalkan lebih tujuh tahun lalu dalam python 3.7:
sorted() dan list.sort() telah dioptimumkan untuk kes biasa sehingga 40-75% lebih pantas. (Disumbangkan oleh Elliot Gorokhovsky dalam bpo-28685.)
Tetapi sebelum kita mula...
Pengenalan Semula Ringkas kepada Isih dalam Python
Apabila anda perlu mengisih senarai dalam python, anda mempunyai dua pilihan:
- Kaedah senarai: list.sort(*, key=None, reverse=False), yang mengisih senarai yang diberikan di tempat
- Fungsi terbina dalam: diisih(boleh lelar, /, *, kunci=Tiada, terbalik= Palsu), yang mengembalikan senarai diisih tanpa mengubah suai hujahnya
Jika anda perlu mengisih mana-mana lelaran terbina dalam lain, anda hanya boleh menggunakan diisih tanpa mengira jenis lelaran atau penjana yang diluluskan sebagai parameter.
isih sentiasa mengembalikan senarai kerana ia menggunakan senarai.isih secara dalaman.
Berikut ialah persamaan kasar pelaksanaan C yang diisih CPython yang ditulis semula dalam python tulen:
def sorted(iterable: Iterable[Any], key=None, reverse=False): new_list = list(iterable) new_list.sort(key=key, reverse=reverse) return new_list
Ya, semudah itu.
Bagaimana Python Membuat Isih Lebih Cepat
Seperti yang dinyatakan dalam dokumentasi dalaman Python untuk pengisihan:
Adakalanya mungkin untuk menggantikan perbandingan khusus jenis yang lebih pantas untuk PyObject_RichCompareBool generik yang lebih perlahan
Dan secara ringkasnya pengoptimuman ini boleh diterangkan seperti berikut:
Apabila senarai adalah homogen, Python menggunakan fungsi perbandingan jenis khusus
Apakah Senarai Homogen?
Senarai homogen ialah senarai yang mengandungi unsur satu jenis sahaja.
Contohnya:
homogeneous = [1, 2, 3, 4]
Sebaliknya, ini bukan senarai homogen:
heterogeneous = [1, "2", (3, ), {'4': 4}]
Menariknya, tutorial Python rasmi menyatakan:
Senarai boleh berubah dan elemennya biasanya homogen dan diakses dengan mengulangi senarai
Nota sampingan tentang tupel
Tutorial yang sama menyatakan:
Tuples adalah tidak berubah dan biasanya mengandungi jujukan heterogen unsur
Jadi, jika anda tertanya-tanya bila hendak menggunakan tuple atau senarai, berikut ialah peraturan praktikal:
jika elemen adalah jenis yang sama, gunakan senarai, jika tidak gunakan tuple
Tunggu, dan bagaimana pula dengan tatasusunan?
Python melaksanakan objek bekas tatasusunan homogen untuk nilai angka.
Walau bagaimanapun, pada python 3.12, tatasusunan tidak melaksanakan kaedah isihan mereka sendiri.
Satu-satunya cara untuk mengisihnya ialah dengan menggunakan diisih, yang secara dalaman mencipta senarai daripada tatasusunan, memadamkan sebarang maklumat berkaitan jenis dalam proses.
Mengapa Menggunakan Fungsi Perbandingan Khusus Jenis Membantu?
Perbandingan dalam python adalah mahal, kerana Python melakukan pelbagai semakan sebelum melakukan sebarang perbandingan sebenar.
Berikut ialah penjelasan ringkas tentang perkara yang berlaku di bawah hud apabila anda membandingkan dua nilai dalam python:
- Python menyemak bahawa nilai yang dihantar kepada fungsi perbandingan bukan NULL
- Jika nilai daripada jenis yang berbeza, tetapi operan kanan ialah subjenis kiri, Python menggunakan fungsi perbandingan operan kanan, tetapi diterbalikkan (mis., ia akan menggunakan < untuk >)
- Jika nilai adalah jenis yang sama, atau jenis yang berbeza tetapi bukan subjenis yang lain:
- Python akan mencuba dahulu fungsi perbandingan operan kiri
- Jika gagal, ia akan mencuba fungsi perbandingan operan kanan, tetapi diterbalikkan.
- Jika itu juga gagal, dan perbandingan adalah untuk kesamaan atau ketidaksamaan, ia akan mengembalikan perbandingan identiti (Benar untuk nilai yang merujuk kepada objek yang sama dalam ingatan)
- Jika tidak, ia menimbulkan TypeError
Selain itu, fungsi perbandingan masing-masing jenis melaksanakan semakan tambahan.
For example, when comparing strings, Python will check if the string characters take more than one byte of memory, and float comparison will compare a pair of float's and a float and an int differently.
A more detailed explanation and diagram can be found here: Adding Data-Aware Sort Optimizations to CPython
Before this optimization was introduced, Python had to execute all this various type-specific and non-type-specific checks every time two values were compared during sorting.
Checking List Element's Types in Advance
There's no magical way to know if all the elements of a list are of the same type other than to iterate over the list and check each element.
Python does almost exactly that — checking the types of sorting keys generated by key function passed to list.sort or sorted as a parameter
Constructing a List of Keys
If a key function is provided, Python uses it to construct a list of keys, otherwise it uses the list's own values as sorting keys.
In an oversimplified manner, keys construction can be expressed as the following python code.
if key is None: keys = list_items else: keys = [key(list_item) for list_item in list_item]
Note, that keys used internally in CPython are a C array of CPython object references, and not a Python list
Once the keys are constructed, Python checks their types.
Checking Key's Type
When checking the types of keys, Python's sorting algorithm tries to determine if all elements in the keys array are either str, int, float or tuple, or simply of the same type, with some constraints for base types.
It's worth noting that checking the types of the keys adds some extra work up front. Python does this because it usually pays off by making the actual sorting faster, especially for longer lists.
int constraints
int should not be a bignum
Practically this means that for this optimization to work, integer should be less than 2^30 - 1 (this may vary depending on the platform)
As a side note, here is a great article which explains how Python handles big integers: # How python implements super long integers?
str constraints
All characters of a string should take less than 1 byte of memory, meaning that they should be represented by integer values in the range of 0-255
In practice, this means that strings should consist only of Latin characters, spaces, and some special characters found in the ASCII table.
float constraints
There are no constraints for floats in order for this optimization to work.
tuple constraints
- Only the first element's type is checked
- This element itself should not be a tuple itself
- If all tuples share the same type for their first element, the comparison optimization is applied to them
- All other elements are compared as usual
How Can I Apply This Knowledge?
First of all, isn’t it fascinating to know?
Secondly, mentioning this knowledge could be a nice touch in a Python Developer interview.
As for actual code development, understanding this optimization can help you improve sorting performance.
Optimize by Selecting the Type of Values Wisely
According to the benchmark in the PR that introduced this optimization, sorting a list that consists only of floats rather than a list of floats with even a single integer at the end is almost twice as fast.
So when it's time to optimize, transforming list like this
floats_and_int = [1.0, -1.0, -0.5, 3]
Into list that looks like this
just_floats = [1.0, -1.0, -0.5, 3.0] # note that 3.0 is a float now
might improve performance.
Optimize by Using Keys for Lists of Objects
While Python's sorting optimization works well with built-in types, it's important to understand how it interacts with custom classes.
When sorting objects of custom classes, Python relies on the comparison methods you define, such as __lt__ (less than) or __gt__ (greater than).
However, the type-specific optimization doesn't apply to custom classes.
Python will always use the general comparison method for these objects.
Here's an example:
class MyClass: def __init__(self, value): self.value = value def __lt__(self, other): return self.value < other.value my_list = [MyClass(3), MyClass(1), MyClass(2)] sorted_list = sorted(my_list)
In this case, Python will use the __lt__ method for comparisons, but it won't benefit from the type-specific optimization. The sorting will still work correctly, but it may not be as fast as sorting built-in types.
If performance is critical when sorting custom objects, consider using a key function that returns a built-in type:
sorted_list = sorted(my_list, key=lambda x: x.value)
Afterword
Premature optimization, especially in Python, is evil.
Anda tidak seharusnya mereka bentuk keseluruhan aplikasi anda mengikut pengoptimuman khusus dalam CPython, tetapi adalah baik untuk mengetahui pengoptimuman ini: mengetahui alatan anda dengan baik ialah cara untuk menjadi pembangun yang lebih mahir.
Berhati-hati dengan pengoptimuman seperti ini membolehkan anda memanfaatkannya apabila keadaan memerlukannya, terutamanya apabila prestasi menjadi kritikal:
Pertimbangkan senario di mana pengisihan anda berdasarkan cap masa: menggunakan senarai integer homogen (cap masa Unix) dan bukannya objek masa tarikh boleh memanfaatkan pengoptimuman ini dengan berkesan.
Walau bagaimanapun, adalah penting untuk diingat bahawa kebolehbacaan dan kebolehselenggaraan kod harus diutamakan daripada pengoptimuman tersebut.
Walaupun penting untuk mengetahui tentang butiran peringkat rendah ini, adalah sama pentingnya untuk menghargai abstraksi peringkat tinggi Python yang menjadikannya bahasa yang begitu produktif.
Python ialah bahasa yang menakjubkan, dan meneroka kedalamannya boleh membantu anda memahaminya dengan lebih baik dan menjadi pengaturcara Python yang lebih baik.
Atas ialah kandungan terperinci Cara Pengoptimuman Perbandingan Menjadikan Pengisihan Python Lebih Cepat. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undress AI Tool
Gambar buka pakaian secara percuma

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas

Polimorfisme adalah konsep teras dalam pengaturcaraan berorientasikan objek Python, merujuk kepada "satu antara muka, pelbagai pelaksanaan", yang membolehkan pemprosesan bersatu pelbagai jenis objek. 1. Polimorfisme dilaksanakan melalui penulisan semula kaedah. Subkelas boleh mentakrifkan semula kaedah kelas induk. Sebagai contoh, kaedah bercakap () kelas haiwan mempunyai pelaksanaan yang berbeza dalam subkelas anjing dan kucing. 2. Penggunaan praktikal polimorfisme termasuk memudahkan struktur kod dan meningkatkan skalabilitas, seperti memanggil kaedah cabutan () secara seragam dalam program lukisan grafik, atau mengendalikan tingkah laku umum watak -watak yang berbeza dalam pembangunan permainan. 3. Polimorfisme pelaksanaan Python perlu memenuhi: Kelas induk mentakrifkan kaedah, dan kelas kanak -kanak mengatasi kaedah, tetapi tidak memerlukan warisan kelas induk yang sama. Selagi objek melaksanakan kaedah yang sama, ini dipanggil "jenis itik". 4. Perkara yang perlu diperhatikan termasuk penyelenggaraan

Parameter adalah ruang letak apabila menentukan fungsi, sementara argumen adalah nilai khusus yang diluluskan ketika memanggil. 1. Parameter kedudukan perlu diluluskan, dan perintah yang salah akan membawa kepada kesilapan dalam hasilnya; 2. Parameter kata kunci ditentukan oleh nama parameter, yang boleh mengubah pesanan dan meningkatkan kebolehbacaan; 3. Nilai parameter lalai diberikan apabila ditakrifkan untuk mengelakkan kod pendua, tetapi objek berubah harus dielakkan sebagai nilai lalai; 4 Args dan *kwargs boleh mengendalikan bilangan parameter yang tidak pasti dan sesuai untuk antara muka umum atau penghias, tetapi harus digunakan dengan berhati -hati untuk mengekalkan kebolehbacaan.

Iterator adalah objek yang melaksanakan kaedah __iter __ () dan __Next __ (). Penjana adalah versi Iterator yang dipermudahkan, yang secara automatik melaksanakan kaedah ini melalui kata kunci hasil. 1. Iterator mengembalikan elemen setiap kali dia memanggil seterusnya () dan melemparkan pengecualian berhenti apabila tidak ada lagi elemen. 2. Penjana menggunakan definisi fungsi untuk menghasilkan data atas permintaan, menjimatkan memori dan menyokong urutan tak terhingga. 3. Menggunakan Iterator apabila memproses set sedia ada, gunakan penjana apabila menghasilkan data besar secara dinamik atau penilaian malas, seperti garis pemuatan mengikut baris apabila membaca fail besar. NOTA: Objek yang boleh diperolehi seperti senarai bukanlah pengaliran. Mereka perlu dicipta semula selepas pemalar itu sampai ke penghujungnya, dan penjana hanya boleh melintasi sekali.

Kaedah kelas adalah kaedah yang ditakrifkan dalam python melalui penghias @classmethod. Parameter pertamanya adalah kelas itu sendiri (CLS), yang digunakan untuk mengakses atau mengubah keadaan kelas. Ia boleh dipanggil melalui kelas atau contoh, yang mempengaruhi seluruh kelas dan bukannya contoh tertentu; Sebagai contoh, dalam kelas orang, kaedah show_count () mengira bilangan objek yang dibuat; Apabila menentukan kaedah kelas, anda perlu menggunakan penghias @classmethod dan namakan parameter pertama CLS, seperti kaedah change_var (new_value) untuk mengubah suai pembolehubah kelas; Kaedah kelas adalah berbeza daripada kaedah contoh (parameter diri) dan kaedah statik (tiada parameter automatik), dan sesuai untuk kaedah kilang, pembina alternatif, dan pengurusan pembolehubah kelas. Kegunaan biasa termasuk:

Kunci untuk menangani pengesahan API adalah untuk memahami dan menggunakan kaedah pengesahan dengan betul. 1. Apikey adalah kaedah pengesahan yang paling mudah, biasanya diletakkan dalam tajuk permintaan atau parameter URL; 2. BasicAuth menggunakan nama pengguna dan kata laluan untuk penghantaran pengekodan Base64, yang sesuai untuk sistem dalaman; 3. OAuth2 perlu mendapatkan token terlebih dahulu melalui client_id dan client_secret, dan kemudian bawa bearertoken dalam header permintaan; 4. Untuk menangani tamat tempoh token, kelas pengurusan token boleh dikemas dan secara automatik menyegarkan token; Singkatnya, memilih kaedah yang sesuai mengikut dokumen dan menyimpan maklumat utama adalah kunci.

MagicMethods Python (atau kaedah dunder) adalah kaedah khas yang digunakan untuk menentukan tingkah laku objek, yang bermula dan berakhir dengan garis bawah dua. 1. Mereka membolehkan objek bertindak balas terhadap operasi terbina dalam, seperti tambahan, perbandingan, perwakilan rentetan, dan sebagainya; 2. Kes penggunaan biasa termasuk inisialisasi objek dan perwakilan (__init__, __repr__, __str__), operasi aritmetik (__add__, __sub__, __mul__) dan operasi perbandingan (__eq__, ___lt__); 3. Apabila menggunakannya, pastikan tingkah laku mereka memenuhi jangkaan. Sebagai contoh, __repr__ harus mengembalikan ungkapan objek refortable, dan kaedah aritmetik harus mengembalikan contoh baru; 4. Perkara yang berlebihan atau mengelirukan harus dielakkan.

Mekanisme pengumpulan sampah Python secara automatik menguruskan memori melalui pengiraan rujukan dan pengumpulan sampah berkala. Kaedah terasnya adalah penghitungan rujukan, yang segera melepaskan memori apabila bilangan rujukan objek adalah sifar; Tetapi ia tidak dapat mengendalikan rujukan bulat, jadi modul pengumpulan sampah (GC) diperkenalkan untuk mengesan dan membersihkan gelung. Pengumpulan sampah biasanya dicetuskan apabila kiraan rujukan berkurangan semasa operasi program, perbezaan peruntukan dan pelepasan melebihi ambang, atau apabila gc.collect () dipanggil secara manual. Pengguna boleh mematikan kitar semula automatik melalui gc.disable (), secara manual melaksanakan gc.collect (), dan menyesuaikan ambang untuk mencapai kawalan melalui gc.set_threshold (). Tidak semua objek mengambil bahagian dalam kitar semula gelung. Sekiranya objek yang tidak mengandungi rujukan diproses dengan mengira rujukan, ia terbina dalam

Pythonmanagesmemoryautomatically leverenceCountingandagarbageCollector.referenceCountingTrackShowmanyvariablesreferoanobject, dan yang mana -mana, dan yang mana -mana
