Saat Anda membuat kode dalam bahasa lain, terkadang Anda akan membuat cakupan blok, seperti ini:
statement
...
statement
{
statement
...
statement
}
statement
...
statement
Salah satu tujuan (dari banyak) adalah untuk meningkatkan keterbacaan kode: untuk menunjukkan bahwa pernyataan tertentu membentuk unit logis atau variabel lokal tertentu hanya digunakan di blok itu.
Apakah ada cara idiomatik untuk melakukan hal yang sama dengan Python?
One purpose (of many) is to improve code readability
- Kode Python, ditulis dengan benar (yaitu, mengikuti zen python ) tidak perlu hiasan seperti itu agar dapat dibaca. Faktanya, ini adalah salah satu dari (banyak) hal yang saya suka tentang Python.__exit__
danwith
pernyataan, mengubahglobals()
tetapi saya gagal.Jawaban:
Tidak, tidak ada dukungan bahasa untuk membuat cakupan blok.
Konstruksi berikut membuat ruang lingkup:
sumber
Cara idiomatik dalam Python adalah dengan membuat fungsi Anda tetap pendek. Jika Anda merasa membutuhkan ini, lakukan refactor kode Anda! :)
Python membuat ruang lingkup baru untuk setiap modul, kelas, fungsi, ekspresi generator, pemahaman dikt, pemahaman set dan di Python 3.x juga untuk setiap pemahaman daftar. Selain itu, tidak ada cakupan bersarang di dalam fungsi.
sumber
Anda dapat melakukan sesuatu yang mirip dengan cakupan blok C ++ dengan Python dengan mendeklarasikan fungsi di dalam fungsi Anda dan kemudian segera memanggilnya. Sebagai contoh:
def my_func(): shared_variable = calculate_thing() def do_first_thing(): ... = shared_variable do_first_thing() def do_second_thing(): foo(shared_variable) ... do_second_thing()
Jika Anda tidak yakin mengapa Anda ingin melakukan ini, maka video ini mungkin bisa meyakinkan Anda.
Prinsip dasarnya adalah untuk mencakup semuanya seketat mungkin tanpa memasukkan 'sampah' (jenis / fungsi tambahan) ke dalam cakupan yang lebih luas daripada yang benar-benar diperlukan - Tidak ada orang lain yang ingin menggunakan
do_first_thing()
metode tersebut misalnya sehingga tidak boleh tercakup di luar fungsi panggilan.sumber
Saya setuju bahwa tidak ada cakupan blok. Tapi satu tempat di python 3 membuatnya Tampak seolah-olah memiliki lingkup blok.
apa yang terjadi yang memberikan tampilan ini? Ini bekerja dengan baik di python 2. tetapi untuk membuat variabel kebocoran berhenti di python 3 mereka telah melakukan trik ini dan perubahan ini membuatnya tampak seolah-olah memiliki lingkup blok di sini.
Biar saya jelaskan.
Sesuai dengan gagasan ruang lingkup, ketika kami memperkenalkan variabel dengan nama yang sama di dalam lingkup yang sama, nilainya harus dimodifikasi.
inilah yang terjadi di python 2
>>> x = 'OLD' >>> sample = [x for x in 'NEW'] >>> x 'W'
Tetapi di python 3 meskipun variabel dengan nama yang sama diperkenalkan itu tidak menimpa, pemahaman daftar bertindak seperti kotak pasir untuk beberapa alasan dan sepertinya membuat ruang lingkup baru di dalamnya.
>>> x = 'OLD' >>> sample = [x for x in 'NEW'] >>> x 'OLD'
dan jawaban ini bertentangan dengan pernyataan penjawab @ Thomas. Satu-satunya cara untuk membuat ruang lingkup adalah fungsi, kelas, atau modul karena ini terlihat seperti satu tempat lain untuk membuat ruang lingkup baru.
sumber
Modul (dan paket) adalah cara Pythonic yang bagus untuk membagi program Anda menjadi ruang nama terpisah, yang tampaknya menjadi tujuan implisit dari pertanyaan ini. Memang, saat saya mempelajari dasar-dasar Python, saya merasa frustrasi dengan kurangnya fitur cakupan blok. Namun begitu saya memahami modul Python, saya dapat dengan lebih elegan mewujudkan tujuan saya sebelumnya tanpa perlu cakupan blok.
Sebagai motivasi, dan untuk mengarahkan orang ke arah yang benar, menurut saya akan berguna untuk memberikan contoh eksplisit dari beberapa konstruksi pelingkupan Python. Pertama saya menjelaskan upaya saya yang gagal dalam menggunakan kelas Python untuk mengimplementasikan lingkup blok. Selanjutnya saya menjelaskan bagaimana saya mencapai sesuatu yang lebih berguna menggunakan modul Python. Di akhir saya menguraikan aplikasi praktis dari paket untuk memuat dan memfilter data.
Mencoba lingkup blok dengan kelas
Untuk beberapa saat saya berpikir bahwa saya telah mencapai lingkup blok dengan menempelkan kode di dalam deklarasi kelas:
x = 5 class BlockScopeAttempt: x = 10 print(x) # Output: 10 print(x) # Output: 5
Sayangnya ini rusak ketika suatu fungsi didefinisikan:
x = 5 class BlockScopeAttempt: x = 10 print(x) # Output: 10 def printx2(): print(x) printx2() # Output: 5!!!
Itu karena fungsi yang didefinisikan dalam kelas menggunakan cakupan global. Cara termudah (meskipun bukan satu-satunya) untuk memperbaikinya adalah dengan menentukan kelas secara eksplisit:
x = 5 class BlockScopeAttempt: x = 10 print(x) # Output: 10 def printx2(): print(BlockScopeAttempt.x) # Added class name printx2() # Output: 10
Ini tidak begitu elegan karena seseorang harus menulis fungsi secara berbeda tergantung pada apakah mereka dimuat dalam sebuah kelas atau tidak.
Hasil yang lebih baik dengan modul Python
Modul sangat mirip dengan kelas statis, tetapi modul jauh lebih bersih menurut pengalaman saya. Untuk melakukan hal yang sama dengan modul, saya membuat file yang dipanggil
my_module.py
di direktori kerja saat ini dengan konten berikut:x = 10 print(x) # (A) def printx(): global x print(x) # (B)
Kemudian di file utama saya atau sesi interaktif (misalnya Jupyter), saya lakukan
x = 5 import my_module # Output: 10 from (A) my_module.printx() # Output: 10 from (B) print(x) # Output: 5
Sebagai penjelasan, setiap file Python mendefinisikan modul yang memiliki namespace global sendiri. Mengimpor modul memungkinkan Anda mengakses variabel di namespace ini dengan
.
sintaks.Jika Anda bekerja dengan modul dalam sesi interaktif, Anda dapat mengeksekusi dua baris ini di awal
%load_ext autoreload %autoreload 2
dan modul akan dimuat ulang secara otomatis saat file terkait diubah.
Paket untuk memuat dan memfilter data
Ide paket adalah sedikit perluasan dari konsep modul. Paket adalah direktori yang berisi file (mungkin kosong)
__init__.py
, yang dijalankan saat diimpor. Modul / paket dalam direktori ini dapat diakses dengan.
sintaks.Untuk analisis data, saya sering kali perlu membaca file data besar dan kemudian secara interaktif menerapkan berbagai filter. Membaca file membutuhkan waktu beberapa menit, jadi saya hanya ingin melakukannya sekali. Berdasarkan apa yang saya pelajari di sekolah tentang pemrograman berorientasi objek, saya dulu percaya bahwa seseorang harus menulis kode untuk memfilter dan memuat sebagai metode di kelas. Kerugian utama dari pendekatan ini adalah jika saya kemudian mendefinisikan ulang filter saya, definisi kelas saya berubah, jadi saya harus memuat ulang seluruh kelas, termasuk datanya.
Saat ini dengan Python, saya mendefinisikan sebuah paket bernama
my_data
yang berisi submodul bernamaload
danfilter
. Di dalamfilter.py
I dapat melakukan impor relatif:from .load import raw_data
Jika saya memodifikasi
filter.py
, makaautoreload
akan mendeteksi perubahan. Itu tidak memuat ulangload.py
, jadi saya tidak perlu memuat ulang data saya. Dengan cara ini saya dapat membuat prototipe kode pemfilteran saya di notebook Jupyter, membungkusnya sebagai fungsi, dan kemudian memotong-tempel dari notebook saya langsung kefilter.py
. Mengetahui hal ini merevolusi alur kerja saya, dan mengubah saya dari seorang yang skeptis menjadi penganut “Zen of Python”.sumber