Kebetulan bahwa sejak 2012 saya telah mengembangkan browser open source, menjadi satu-satunya programmer. Dengan Python dengan sendirinya. Peramban bukanlah hal yang termudah, sekarang di bagian utama proyek ini terdapat lebih dari 1000 modul dan lebih dari 120.000 baris kode Python. Secara total, ini akan menjadi satu setengah kali lebih banyak dengan proyek satelit.
Pada titik tertentu, saya bosan mengotak-atik lantai impor di awal setiap file, dan saya memutuskan untuk menangani masalah ini untuk selamanya. Jadi perpustakaan
smart_import lahir (
github ,
pypi ).
Idenya cukup sederhana. Setiap proyek kompleks pada akhirnya membentuk perjanjiannya sendiri untuk menamai semuanya.
Jika perjanjian ini diubah menjadi aturan yang lebih formal, maka setiap entitas dapat diimpor secara otomatis dengan nama variabel yang terkait dengannya.Misalnya, Anda tidak perlu menulis
import math
untuk mengakses
math.pi
- kita
math.pi
dapat memahami bahwa dalam hal ini
math
adalah modul perpustakaan standar.
Impor pintar mendukung Python> = 3.5. Perpustakaan sepenuhnya dicakup oleh tes,
cakupan> 95% . Saya sudah menggunakannya sendiri selama satu tahun sekarang.
Untuk detailnya, saya mengundang Anda ke Cat.
Bagaimana cara kerjanya secara umum?
Jadi, kode dari gambar header berfungsi sebagai berikut:
- Selama panggilan ke
smart_imports.all()
perpustakaan membangun AST dari modul dari mana panggilan itu dibuat; - Temukan variabel yang tidak diinisialisasi;
- Kami menjalankan nama masing-masing variabel melalui urutan aturan yang mencoba menemukan modul (atau atribut modul) yang diperlukan untuk impor berdasarkan nama. Jika aturan telah menemukan entitas yang diperlukan, aturan berikut ini tidak dicentang.
- Modul yang ditemukan dimuat, diinisialisasi dan ditempatkan di namespace global (atau atribut yang diperlukan dari modul ini ditempatkan di sana).
Variabel yang tidak diinisialisasi dicari di seluruh kode, termasuk sintaks baru.
Impor otomatis diaktifkan hanya untuk komponen proyek yang secara eksplisit memanggil
smart_imoprts.all()
. Selain itu, penggunaan impor pintar tidak melarang penggunaan impor konvensional. Ini memungkinkan Anda untuk mengimplementasikan perpustakaan secara bertahap, serta menyelesaikan dependensi siklik yang rumit.
Pembaca yang teliti akan memperhatikan bahwa modul AST dibangun dua kali:
- CPython membangunnya untuk pertama kali selama impor modul;
- Kali kedua smart_import membangunnya saat panggilan ke
smart_imports.all()
.
AST benar-benar dapat dibangun hanya sekali (untuk ini Anda perlu mengintegrasikan ke dalam proses impor modul menggunakan kait impor diimplementasikan dalam
PEP-0302 , tetapi solusi ini memperlambat impor.
Mengapa menurut Anda begitu?Membandingkan kinerja dua implementasi (dengan dan tanpa kait), saya sampai pada kesimpulan bahwa ketika mengimpor modul, CPython membangun AST dalam struktur data internal (C-shh). Mengubahnya ke struktur data Python lebih mahal daripada membangun pohon dari sumber menggunakan modul
ast .
Tentu saja, AST dari setiap modul dibangun dan dianalisis hanya sekali per peluncuran.
Aturan Impor Default
Perpustakaan dapat digunakan tanpa konfigurasi tambahan. Secara default, itu mengimpor modul sesuai dengan aturan berikut:
- Secara kebetulan, nama itu mencari modul di sebelah yang sekarang (di direktori yang sama).
- Periksa modul perpustakaan standar:
- dengan pencocokan tepat nama untuk paket tingkat atas;
- untuk paket dan modul bersarang, periksa nama majemuk, ganti titik dengan garis bawah. Misalnya,
os.path
akan diimpor jika variabel os_path
.
- Dengan pencocokan nama yang tepat, ia mencari paket pihak ketiga yang diinstal. Misalnya, permintaan paket terkenal.
Performa
Impor pintar tidak memengaruhi kinerja program, tetapi meningkatkan waktu yang diperlukan untuk memulai.
Karena pembangunan kembali AST, waktu lari pertama meningkat sekitar 1,5-2 kali. Untuk proyek kecil ini tidak signifikan. Dalam proyek-proyek besar, waktu start-up menderita dari struktur ketergantungan antara modul daripada dari waktu impor modul tertentu.
Ketika impor pintar menjadi populer, saya menulis ulang pekerjaan dari AST ke C - ini akan secara signifikan mengurangi biaya startup.
Untuk mempercepat pemuatan, hasil pemrosesan modul AST dapat di-cache pada sistem file. Caching diaktifkan di konfigurasi. Tentu saja, cache dinonaktifkan ketika Anda mengubah sumbernya.
Waktu start-up dipengaruhi oleh daftar aturan pencarian modul dan urutannya. Karena beberapa aturan menggunakan fungsionalitas Python standar untuk mencari modul. Anda dapat mengecualikan pengeluaran ini dengan secara eksplisit menunjukkan korespondensi nama dan modul menggunakan aturan "Nama Khusus" (lihat di bawah).
Konfigurasi
Konfigurasi default telah dijelaskan sebelumnya. Seharusnya cukup untuk bekerja dengan perpustakaan standar dalam proyek-proyek kecil.
Konfigurasi default { "cache_dir": null, "rules": [{"type": "rule_local_modules"}, {"type": "rule_stdlib"}, {"type": "rule_predefined_names"}, {"type": "rule_global_modules"}] }
Jika perlu, konfigurasi yang lebih kompleks dapat diletakkan pada sistem file.
Contoh konfigurasi kompleks (dari browser).
Selama panggilan ke
smart_import.all()
perpustakaan menentukan posisi modul panggilan pada sistem file dan mulai mencari file
smart_imports.json
dalam arah dari direktori saat ini ke root. Jika file tersebut ditemukan, itu dianggap sebagai konfigurasi untuk modul saat ini.
Anda dapat menggunakan beberapa konfigurasi berbeda (menempatkannya di direktori yang berbeda).
Tidak ada banyak opsi konfigurasi sekarang:
{ // AST. // null — . "cache_dir": null|"string", // . "rules": [] }
Aturan Impor
Urutan menentukan aturan dalam konfigurasi menentukan urutan aplikasi mereka. Aturan pertama yang berfungsi menghentikan pencarian lebih lanjut untuk impor.
Dalam contoh-contoh konfigurasi, aturan rule_predefined_names akan sering muncul di
rule_predefined_names
, perlu bahwa fungsi bawaan (misalnya,
print
) dikenali dengan benar.
Aturan 1: Nama yang Ditentukan sebelumnya
Aturan ini memungkinkan Anda untuk mengabaikan nama yang telah ditentukan seperti
__file__
dan fungsi
__file__
seperti
print
.
Aturan 2: Modul Lokal
Cek apakah ada modul dengan nama yang ditentukan di sebelah modul saat ini (di direktori yang sama). Jika ada, impor saja.
Aturan 3: Modul Global
Mencoba mengimpor modul secara langsung dengan nama. Misalnya, modul
permintaan .
Aturan 4: Nama Khusus
Sesuai dengan nama modul tertentu atau atributnya. Kepatuhan ditunjukkan dalam aturan konfigurasi.
Aturan 5: Modul Standar
Periksa apakah namanya adalah modul perpustakaan standar. Misalnya
matematika atau
os.path yang berubah menjadi
os_path
.
Ini bekerja lebih cepat daripada aturan untuk mengimpor modul global, karena memeriksa keberadaan modul pada daftar yang di-cache. Daftar untuk setiap versi Python berasal dari sini:
github.com/jackmaney/python-stdlib-listAturan 6: Impor dengan Awalan
Mengimpor modul dengan nama, dari paket yang terkait dengan awalannya. Lebih mudah digunakan ketika Anda memiliki beberapa paket yang digunakan di seluruh kode. Sebagai contoh, modul paket
utils
dapat diakses dengan awalan
utils_
.
Aturan 7: Modul dari paket induk
Jika Anda memiliki sub paket dengan nama yang sama di berbagai bagian proyek (misalnya,
tests
atau
migrations
), Anda dapat memperbolehkan mereka mencari modul untuk diimpor dengan nama dalam paket induk.
Aturan 8: Mengikat paket lain
Untuk modul dari paket tertentu, ini memungkinkan pencarian impor dengan nama dalam paket lain (ditentukan dalam konfigurasi). Dalam kasus saya, aturan ini bermanfaat untuk kasus-kasus ketika saya tidak ingin memperluas pekerjaan aturan sebelumnya (Modul dari paket induk) ke seluruh proyek.
Menambahkan Aturan Anda Sendiri
Menambahkan aturan Anda sendiri cukup sederhana:
- Kami mewarisi dari kelas smart_imports.rules.BaseRule .
- Kami menyadari logika yang diperlukan.
- Daftarkan aturan menggunakan metode smart_imports.rules.register
- Tambahkan aturan ke konfigurasi.
- ???
- Untung
Contoh dapat ditemukan dalam
implementasi aturan saat ini.Untung
Daftar impor multiline di awal setiap sumber telah hilang.
Jumlah baris menurun. Sebelum browser beralih ke impor cerdas, ada 6688 baris yang bertanggung jawab untuk mengimpor. Setelah transisi, 2084 tetap (dua baris smart_import per file + 130 impor, dipanggil secara eksplisit dari fungsi dan tempat yang serupa).
Bonus yang bagus adalah standarisasi nama dalam proyek. Kode menjadi lebih mudah dibaca dan lebih mudah untuk ditulis. Tidak perlu memikirkan nama-nama entitas yang diimpor - ada beberapa aturan yang jelas yang mudah diikuti.
Rencana pengembangan
Saya suka ide mendefinisikan properti kode dengan nama variabel, jadi saya akan mencoba mengembangkannya baik dalam impor pintar maupun dalam proyek lain.
Mengenai impor cerdas, saya berencana:
- Tambahkan dukungan untuk versi Python baru.
- Jelajahi kemungkinan mengandalkan praktik komunitas saat ini pada jenis anotasi kode.
- Jelajahi kemungkinan membuat impor malas.
- Terapkan utilitas untuk pembuatan otomatis konfigurasi dari kode sumber dan refactoring sumber untuk menggunakan smart_import.
- Tulis ulang bagian dari kode C untuk mempercepat pekerjaan dengan AST.
- Untuk mengembangkan integrasi dengan linter dan IDE jika mereka memiliki masalah dengan analisis kode tanpa impor eksplisit.
Selain itu, saya tertarik dengan pendapat Anda tentang perilaku default perpustakaan dan aturan impor.
Terima kasih telah mengatasi lembaran teks ini :-D