cari
Rumahpembangunan bahagian belakangTutorial PythonBagaimana saya menambah sokongan untuk fungsi bersarang dalam Python bytecode

How I added support for nested functions in 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)
}
</bytecode>

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)
}
</bytecode>

Terima kasih kerana mempertimbangkan kod itu.

Kami kini menyokong panggilan fungsi bersarang! Apa yang berubah?

  1. 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.
  2. 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:

  1. 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).
  2. 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!)
  3. 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)
}
</bytecode>

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!

Kenyataan
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Bagaimana anda menambah elemen ke senarai python?Bagaimana anda menambah elemen ke senarai python?May 04, 2025 am 12:17 AM

ToAppendElementStoapyThonList, useTheAppend () methodforsingleelements, extend () formultipleelements, andInsert () forspecificposition.1) useAppend () foraddingOneElementAttheend.2)

Bagaimana anda membuat senarai python? Beri contoh.Bagaimana anda membuat senarai python? Beri contoh.May 04, 2025 am 12:16 AM

TOCREATEAPYTHONLIST, USESQUAREBRACKETS [] danSeparatateItemSwithCommas.1) listsaredynamicandCanHoldMixedDatypes.2) UseAppend (), mengalih keluar (), danSlicingFormApulation.3)

Bincangkan kes penggunaan dunia sebenar di mana penyimpanan dan pemprosesan data berangka yang cekap adalah kritikal.Bincangkan kes penggunaan dunia sebenar di mana penyimpanan dan pemprosesan data berangka yang cekap adalah kritikal.May 04, 2025 am 12:11 AM

Dalam bidang kewangan, penyelidikan saintifik, penjagaan perubatan dan AI, adalah penting untuk menyimpan dan memproses data berangka dengan cekap. 1) Dalam Kewangan, menggunakan memori yang dipetakan fail dan perpustakaan Numpy dapat meningkatkan kelajuan pemprosesan data dengan ketara. 2) Dalam bidang penyelidikan saintifik, fail HDF5 dioptimumkan untuk penyimpanan data dan pengambilan semula. 3) Dalam penjagaan perubatan, teknologi pengoptimuman pangkalan data seperti pengindeksan dan pembahagian meningkatkan prestasi pertanyaan data. 4) Dalam AI, data sharding dan diedarkan latihan mempercepatkan latihan model. Prestasi dan skalabiliti sistem dapat ditingkatkan dengan ketara dengan memilih alat dan teknologi yang tepat dan menimbang perdagangan antara kelajuan penyimpanan dan pemprosesan.

Bagaimana anda membuat array python? Beri contoh.Bagaimana anda membuat array python? Beri contoh.May 04, 2025 am 12:10 AM

Pythonarraysarecreatedusingthearraymodule, notbuilt-inlikelists.1) importTheArrayModule.2) specifythetypecode, cth., 'I'forintegers.3) Initializewithvalues.arraysofferbettermemoryficiencyficorhomogeneousdatabutflex.

Apakah beberapa alternatif untuk menggunakan garis shebang untuk menentukan penterjemah python?Apakah beberapa alternatif untuk menggunakan garis shebang untuk menentukan penterjemah python?May 04, 2025 am 12:07 AM

Sebagai tambahan kepada garis shebang, terdapat banyak cara untuk menentukan penterjemah python: 1. Gunakan perintah python terus dari baris arahan; 2. Gunakan fail batch atau skrip shell; 3. Gunakan alat binaan seperti membuat atau cmake; 4. Gunakan pelari tugas seperti Invoke. Setiap kaedah mempunyai kelebihan dan kekurangannya, dan penting untuk memilih kaedah yang sesuai dengan keperluan projek.

Bagaimanakah pilihan antara senarai dan tatasusunan memberi kesan kepada prestasi keseluruhan aplikasi Python yang berurusan dengan dataset yang besar?Bagaimanakah pilihan antara senarai dan tatasusunan memberi kesan kepada prestasi keseluruhan aplikasi Python yang berurusan dengan dataset yang besar?May 03, 2025 am 12:11 AM

Forhandlinglargedatasetsinpython, usenumpyarraysforbetterperformance.1) numpyarraysarememory-efisien danfasterfornumumerical.2) mengelakkan yang tidak dapat dipertahankan.3)

Jelaskan bagaimana memori diperuntukkan untuk senarai berbanding tatasusunan dalam Python.Jelaskan bagaimana memori diperuntukkan untuk senarai berbanding tatasusunan dalam Python.May 03, 2025 am 12:10 AM

Inpython, listsusedynamicMemoryAllocationwithover-peruntukan, pemecahan yang tidak dapat dilaksanakan.1) listsallocatemoremoremorythanneedinitial, resizingwhennessary.2) numpyarraysallocateExactMemoreForelements, menawarkanpredictableSabeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeBeat.

Bagaimana anda menentukan jenis data elemen dalam array python?Bagaimana anda menentukan jenis data elemen dalam array python?May 03, 2025 am 12:06 AM

Inpython, YouCansspectHedatypeyFeleMeremodelerernspant.1) Usenpynernrump.1) usenpynerp.dloatp.ploatm64, formor preciscontrolatatypes.

See all articles

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

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

Alat panas

SublimeText3 Linux versi baharu

SublimeText3 Linux versi baharu

SublimeText3 Linux versi terkini

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

PhpStorm versi Mac

PhpStorm versi Mac

Alat pembangunan bersepadu PHP profesional terkini (2018.2.1).

mPDF

mPDF

mPDF ialah perpustakaan PHP yang boleh menjana fail PDF daripada HTML yang dikodkan UTF-8. Pengarang asal, Ian Back, menulis mPDF untuk mengeluarkan fail PDF "dengan cepat" dari tapak webnya dan mengendalikan bahasa yang berbeza. Ia lebih perlahan dan menghasilkan fail yang lebih besar apabila menggunakan fon Unicode daripada skrip asal seperti HTML2FPDF, tetapi menyokong gaya CSS dsb. dan mempunyai banyak peningkatan. Menyokong hampir semua bahasa, termasuk RTL (Arab dan Ibrani) dan CJK (Cina, Jepun dan Korea). Menyokong elemen peringkat blok bersarang (seperti P, DIV),

Muat turun versi mac editor Atom

Muat turun versi mac editor Atom

Editor sumber terbuka yang paling popular