


Bagaimana saya menambah sokongan untuk fungsi bersarang dalam Python bytecode
Saya ingin berkongsi beberapa perkara yang cukup menarik Saya telah belajar tentang Kod bait Python dengan anda, termasuk cara saya menambah sokongan untuk nested berfungsi, tetapi lelaki saya di mesin cetak berkata saya perlu menyimpannya di bawah 500 patah perkataan.
Hari ini minggu cuti, dia mengangkat bahu. Apa yang anda harapkan saya lakukan?
Tidak termasuk coretan kod, saya tawar-menawar.
Baik, dia menyerah kalah.
Adakah anda tahu mengapa kami menggunakan bytecode sejak awal?
Saya baru sahaja mengendalikan mesin cetak, saya percayakan anda.
Cukup adil. Mari mulakan.
Mengapa kami menggunakan bytecode pada mulanya
Memphis, jurubahasa Python saya yang ditulis dalam Rust, mempunyai dua enjin pelaksanaan. Kedua-duanya tidak boleh menjalankan semua kod tetapi kedua-duanya boleh menjalankan beberapa kod.
jurubahasa treewalk saya ialah apa yang anda akan bina jika anda tidak tahu apa yang anda lakukan. ?♂️ Anda menandakan kod Python input, menjana pepohon sintaks abstrak (AST), dan kemudian menjalani pepohon dan menilai setiap nod. Ungkapan mengembalikan nilai dan pernyataan mengubah suai jadual simbol, yang dilaksanakan sebagai satu siri skop yang menghormati peraturan skop Python. Ingat sahaja LEGB pneumonik mudah: tempatan, tertutup, global, terbina.
bytecode VM saya ialah perkara yang anda akan bina jika anda tidak tahu apa yang anda lakukan tetapi mahu bertindak seperti yang anda lakukan. Juga ?♂️. Untuk enjin ini, token dan AST berfungsi sama, tetapi daripada berjalan, kami mula berlari pecut. Kami menghimpun AST menjadi perwakilan perantaraan (IR) selepas ini dikenali sebagai bytecode. Kami kemudiannya mencipta mesin maya (VM) berasaskan tindanan, yang secara konsepnya bertindak seperti CPU, melaksanakan arahan kod bait mengikut turutan, tetapi ia dilaksanakan sepenuhnya dalam perisian.
(Untuk panduan lengkap kedua-dua pendekatan tanpa bertele-tele, Jurubahasa Kerajinan adalah cemerlang.)
Mengapa kita melakukan ini pada mulanya? Hanya ingat dua P: mudah alih dan prestasi. Ingat bagaimana pada awal 2000-an tiada siapa yang akan menutup mulut tentang bagaimana kod bait Java mudah alih? Apa yang anda perlukan hanyalah JVM dan anda boleh menjalankan program Java yang disusun pada mana-mana mesin! Python memilih untuk tidak menggunakan pendekatan ini atas sebab teknikal dan pemasaran, tetapi secara teori prinsip yang sama digunakan. (Secara praktikal, langkah penyusunan adalah berbeza dan saya menyesal membuka tin cacing ini.)
Prestasi adalah masalah besar. Daripada merentasi AST berbilang kali sepanjang hayat program, IR yang disusun adalah perwakilan yang lebih cekap. Kami melihat prestasi yang lebih baik daripada mengelakkan overhed berulang kali melintasi AST, dan struktur ratanya sering menghasilkan ramalan cawangan dan lokasi cache yang lebih baik pada masa jalan.
(Saya tidak menyalahkan anda kerana tidak memikirkan tentang caching jika anda tidak mempunyai latar belakang dalam seni bina komputer—apakah, saya memulakan kerjaya saya dalam industri itu dan saya berfikir tentang caching jauh lebih sedikit daripada yang saya fikirkan tentang cara untuk mengelakkan menulis baris kod yang sama dua kali. Jadi percayakan saya pada bahagian prestasi itu: kepercayaan buta.)
Hai kawan, itu 500 patah perkataan. Kita perlu memuatkan bingkai dan biarkan koyak.
Sudah?! Anda mengecualikan coretan kod?
Tiada coretan kod, kawanku.
Okay okay. Hanya 500 lagi. Saya berjanji.
Konteks penting untuk pembolehubah Python
Saya mendapat agak jauh sebelum membentangkan pelaksanaan VM bytecode saya kira-kira setahun yang lalu: Saya boleh mentakrifkan fungsi dan kelas Python serta memanggil fungsi tersebut dan membuat contoh kelas tersebut. Saya mengekang tingkah laku ini dengan beberapa ujian. Tetapi saya tahu pelaksanaan saya tidak kemas dan saya perlu menyemak semula asas sebelum menambah lebih banyak perkara yang menyeronokkan. Sekarang minggu Krismas dan saya ingin menambah bahan yang menyeronokkan.
Pertimbangkan coretan ini untuk memanggil fungsi, memerhatikan TODO.
fn compile_function_call( &mut self, name: &str, args: &ParsedArguments) ) -> Result<Bytecode, CompileError> { let mut opcodes = vec![]; // We push the args onto the stack in reverse call order so that we will pop // them off in call order. for arg in args.args.iter().rev() { opcodes.extend(self.compile_expr(arg)?); } let (_, index) = self.get_local_index(name); // TODO how does this know if it is a global or local index? this may not be the right // approach for calling a function opcodes.push(Opcode::Call(index)); Ok(opcodes) }
Adakah anda selesai mempertimbangkan? Kami memuatkan hujah fungsi ke dalam timbunan dan "panggil fungsi". Dalam bytecode, semua nama ditukar kepada indeks (kerana akses indeks lebih pantas semasa masa jalan VM), tetapi kami tidak benar-benar mempunyai cara untuk mengetahui sama ada kami berurusan dengan indeks tempatan atau indeks global di sini.
Sekarang pertimbangkan versi yang dipertingkatkan.
fn compile_function_call( &mut self, name: &str, args: &ParsedArguments) ) -> Result<Bytecode, CompileError> { let mut opcodes = vec![self.compile_load(name)]; // We push the args onto the stack in reverse call order so that we will pop // them off in call order. for arg in args.args.iter().rev() { opcodes.extend(self.compile_expr(arg)?); } let argc = opcodes.len() - 1; opcodes.push(Opcode::Call(argc)); Ok(opcodes) }
Terima kasih kerana mempertimbangkan kod itu.
Kami kini menyokong panggilan fungsi bersarang! Apa yang berubah?
- Opcode Panggilan kini mengambil beberapa argumen kedudukan, bukannya indeks kepada fungsi tersebut. Ini mengarahkan VM berapa banyak hujah yang akan muncul daripada timbunan sebelum memanggil fungsi.
- Selepas mengeluarkan argumen dari timbunan, fungsi itu sendiri akan ditinggalkan pada tindanan dan compile_load telah pun mengendalikan skop tempatan berbanding global untuk kami.
LOAD_GLOBAL berbanding LOAD_FAST
Mari kita lihat apa yang dilakukan oleh compile_load.
fn compile_load(&mut self, name: &str) -> Opcode { match self.ensure_context() { Context::Global => Opcode::LoadGlobal(self.get_or_set_nonlocal_index(name)), Context::Local => { // Check locals first if let Some(index) = self.get_local_index(name) { return Opcode::LoadFast(index); } // If not found locally, fall back to globals Opcode::LoadGlobal(self.get_or_set_nonlocal_index(name)) } } }
Terdapat beberapa prinsip utama dalam tindakan di sini:
- Kami memadankan berdasarkan konteks semasa. Mematuhi semantik Python, kami boleh menganggap Context::Global berada di peringkat teratas mana-mana modul (bukan hanya titik masuk skrip anda), dan Context::Local berada di dalam mana-mana blok (iaitu definisi fungsi atau definisi kelas).
- Kami kini membezakan antara indeks tempatan dan indeks bukan tempatan. (Oleh kerana saya menjadi gila cuba mentafsir apa yang dirujuk oleh indeks 0 di tempat yang berbeza, saya memperkenalkan integer bertaip. LocalIndex dan NonlocalIndex menyediakan keselamatan jenis untuk integer tidak bertanda yang tidak ditaip. Saya mungkin menulis tentang perkara ini pada masa hadapan!)
- Kami boleh mengetahui pada masa penyusunan bytecode sama ada pembolehubah tempatan wujud dengan nama tertentu dan jika tidak, pada masa jalan kami akan mencari pembolehubah global. Ini merujuk kepada kedinamikan yang terbina dalam Python: selagi pembolehubah hadir dalam skop global modul itu pada masa fungsi dilaksanakan, nilainya boleh diselesaikan pada masa jalan. Walau bagaimanapun, resolusi dinamik ini datang dengan prestasi prestasi. Walaupun carian pembolehubah tempatan dioptimumkan untuk menggunakan indeks tindanan, carian global memerlukan carian kamus ruang nama global, yang lebih perlahan. Kamus ini ialah pemetaan nama kepada objek, yang mungkin hidup di atas timbunan. Siapa tahu bahawa pepatah "Berfikir secara global, bertindak secara tempatan." sebenarnya merujuk kepada skop Python?
Apa yang ada dalam varname?
Perkara terakhir yang saya akan tinggalkan kepada anda hari ini ialah melihat bagaimana nama pembolehubah ini dipetakan. Dalam coretan kod di bawah, anda akan melihat bahawa indeks tempatan ditemui dalam code.varnames dan indeks bukan tempatan ditemui dalam code.names. Kedua-duanya hidup pada CodeObject, yang mengandungi metadata untuk blok kod bait Python, termasuk pembolehubah dan pemetaan namanya.
fn compile_function_call( &mut self, name: &str, args: &ParsedArguments) ) -> Result<Bytecode, CompileError> { let mut opcodes = vec![]; // We push the args onto the stack in reverse call order so that we will pop // them off in call order. for arg in args.args.iter().rev() { opcodes.extend(self.compile_expr(arg)?); } let (_, index) = self.get_local_index(name); // TODO how does this know if it is a global or local index? this may not be the right // approach for calling a function opcodes.push(Opcode::Call(index)); Ok(opcodes) }
Perbezaan antara nama vakar dan nama menyeksa saya selama berminggu-minggu (CPython memanggil nama_varnamen dan nama_bersama ini), tetapi ia sebenarnya agak mudah. vaname menyimpan nama pembolehubah untuk semua pembolehubah tempatan dalam skop tertentu dan nama melakukan perkara yang sama untuk semua bukan tempatan.
Setelah kami menjejaki ini dengan betul, semua yang lain hanya berfungsi. Pada masa jalanan, VM melihat LOAD_GLOBAL atau LOAD_FAST dan tahu untuk melihat dalam kamus ruang nama global atau tindanan setempat, masing-masing.
Kawan! Encik Gutenberg sedang menelefon dan berkata kami tidak boleh menekan menekan lagi.
Baiklah! baiklah! Saya faham! Mari hantar. ?
Apa yang seterusnya untuk Memphis?
Shh! Lelaki mesin cetak tidak tahu saya sedang menulis kesimpulan, jadi saya akan ringkas.
Dengan skop pembolehubah dan panggilan fungsi di tempat yang kukuh, saya secara beransur-ansur mengalihkan perhatian saya kepada ciri seperti surih tindanan dan sokongan tak segerak. Jika anda suka menyelami kod bait ini atau mempunyai soalan tentang membina penterjemah anda sendiri, saya ingin mendengar daripada anda—berikan ulasan!
Langgan & Simpan [pada apa-apa]
Jika anda ingin mendapatkan lebih banyak siaran seperti ini terus ke peti masuk anda, anda boleh melanggan di sini!
Bekerja Dengan Saya
Saya mentor jurutera perisian untuk menavigasi cabaran teknikal dan pertumbuhan kerjaya dalam persekitaran yang kadangkala bodoh yang menyokong. Jika anda berminat, anda boleh menempah sesi di sini.
Di tempat lain
Selain bimbingan, saya juga menulis tentang pengalaman saya mengemudi bekerja sendiri dan autisme yang didiagnosis lewat. Kurang kod dan bilangan jenaka yang sama.
- Kopi Kesan Tasik, Bab 2 - Dari org titik awal
Atas ialah kandungan terperinci Bagaimana saya menambah sokongan untuk fungsi bersarang dalam Python bytecode. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

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

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

Undress AI Tool
Gambar buka pakaian secara percuma

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











Python lebih mudah dipelajari dan digunakan, manakala C lebih kuat tetapi kompleks. 1. Sintaks Python adalah ringkas dan sesuai untuk pemula. Penaipan dinamik dan pengurusan memori automatik menjadikannya mudah digunakan, tetapi boleh menyebabkan kesilapan runtime. 2.C menyediakan kawalan peringkat rendah dan ciri-ciri canggih, sesuai untuk aplikasi berprestasi tinggi, tetapi mempunyai ambang pembelajaran yang tinggi dan memerlukan memori manual dan pengurusan keselamatan jenis.

Adakah cukup untuk belajar Python selama dua jam sehari? Ia bergantung pada matlamat dan kaedah pembelajaran anda. 1) Membangunkan pelan pembelajaran yang jelas, 2) Pilih sumber dan kaedah pembelajaran yang sesuai, 3) mengamalkan dan mengkaji semula dan menyatukan amalan tangan dan mengkaji semula dan menyatukan, dan anda secara beransur-ansur boleh menguasai pengetahuan asas dan fungsi lanjutan Python dalam tempoh ini.

Python lebih baik daripada C dalam kecekapan pembangunan, tetapi C lebih tinggi dalam prestasi pelaksanaan. 1. Sintaks ringkas Python dan perpustakaan yang kaya meningkatkan kecekapan pembangunan. 2. Ciri-ciri jenis kompilasi dan kawalan perkakasan meningkatkan prestasi pelaksanaan. Apabila membuat pilihan, anda perlu menimbang kelajuan pembangunan dan kecekapan pelaksanaan berdasarkan keperluan projek.

Python dan C masing -masing mempunyai kelebihan sendiri, dan pilihannya harus berdasarkan keperluan projek. 1) Python sesuai untuk pembangunan pesat dan pemprosesan data kerana sintaks ringkas dan menaip dinamik. 2) C sesuai untuk prestasi tinggi dan pengaturcaraan sistem kerana menaip statik dan pengurusan memori manual.

Pythonlistsarepartofthestandardlibrary, sementara

Python cemerlang dalam automasi, skrip, dan pengurusan tugas. 1) Automasi: Sandaran fail direalisasikan melalui perpustakaan standard seperti OS dan Shutil. 2) Penulisan Skrip: Gunakan Perpustakaan Psutil untuk memantau sumber sistem. 3) Pengurusan Tugas: Gunakan perpustakaan jadual untuk menjadualkan tugas. Kemudahan penggunaan Python dan sokongan perpustakaan yang kaya menjadikannya alat pilihan di kawasan ini.

Aplikasi Python dalam pengkomputeran saintifik termasuk analisis data, pembelajaran mesin, simulasi berangka dan visualisasi. 1.Numpy menyediakan susunan pelbagai dimensi yang cekap dan fungsi matematik. 2. Scipy memanjangkan fungsi numpy dan menyediakan pengoptimuman dan alat algebra linear. 3. Pandas digunakan untuk pemprosesan dan analisis data. 4.Matplotlib digunakan untuk menghasilkan pelbagai graf dan hasil visual.

Aplikasi utama Python dalam pembangunan web termasuk penggunaan kerangka Django dan Flask, pembangunan API, analisis data dan visualisasi, pembelajaran mesin dan AI, dan pengoptimuman prestasi. 1. Rangka Kerja Django dan Flask: Django sesuai untuk perkembangan pesat aplikasi kompleks, dan Flask sesuai untuk projek kecil atau sangat disesuaikan. 2. Pembangunan API: Gunakan Flask atau DjangorestFramework untuk membina Restfulapi. 3. Analisis Data dan Visualisasi: Gunakan Python untuk memproses data dan memaparkannya melalui antara muka web. 4. Pembelajaran Mesin dan AI: Python digunakan untuk membina aplikasi web pintar. 5. Pengoptimuman Prestasi: Dioptimumkan melalui pengaturcaraan, caching dan kod tak segerak
