Rumah pembangunan bahagian belakang Tutorial Python Menguasai Pengaturcaraan Meta Ajaib Python: Kod yang Menulis Sendiri

Menguasai Pengaturcaraan Meta Ajaib Python: Kod yang Menulis Sendiri

Dec 08, 2024 am 10:41 AM

Mastering Python

Keupayaan metaprogramming Python benar-benar menarik. Mereka membenarkan kami membengkokkan bahasa mengikut kehendak kami, mencipta kod yang menulis kod. Ia seperti mengajar Python untuk menjadi pengaturcara sendiri!

Mari kita mulakan dengan penjanaan kod. Di sinilah kita mencipta kod Python sebagai rentetan dan kemudian melaksanakannya. Ia mungkin terdengar mudah, tetapi ia sangat berkuasa. Berikut ialah contoh asas:

code = f"def greet(name):\n    print(f'Hello, {{name}}!')"
exec(code)
greet("Alice")
Salin selepas log masuk
Salin selepas log masuk

Ini mencipta fungsi dengan cepat dan kemudian memanggilnya. Tetapi kita boleh pergi lebih jauh. Kami boleh menjana keseluruhan kelas, modul atau algoritma kompleks berdasarkan keadaan masa jalan.

Satu helah hebat ialah menggunakan penjanaan kod untuk konfigurasi. Daripada memuatkan fail konfigurasi, kami boleh menjana kod Python yang mentakrifkan tetapan kami. Ini boleh menjadi lebih pantas dan lebih fleksibel daripada penghuraian konfigurasi tradisional.

Sekarang, mari kita beralih kepada Pokok Sintaks Abstrak (AST). Di sinilah perkara menjadi sangat menarik. AST ialah perwakilan pokok kod Python. Kita boleh menghuraikan sumber Python ke dalam AST, mengubah suainya dan kemudian menyusunnya semula menjadi kod boleh laku.

Berikut ialah contoh mudah yang mengubah suai fungsi untuk menambah pengelogan:

import ast

def add_logging(node):
    if isinstance(node, ast.FunctionDef):
        log_stmt = ast.Expr(ast.Call(
            func=ast.Attribute(
                value=ast.Name(id='print', ctx=ast.Load()),
                attr='__call__',
                ctx=ast.Load()
            ),
            args=[ast.Str(s=f"Calling {node.name}")],
            keywords=[]
        ))
        node.body.insert(0, log_stmt)
    return node

tree = ast.parse("def hello(): print('Hello, world!')")
modified_tree = ast.fix_missing_locations(ast.NodeTransformer().visit(tree))
exec(compile(modified_tree, '<string>', 'exec'))
hello()
Salin selepas log masuk
Salin selepas log masuk

Ini menambah pernyataan cetakan pada permulaan setiap fungsi. Ini contoh mudah, tetapi ia menunjukkan kuasa manipulasi AST. Kita boleh menggunakan ini untuk semua jenis transformasi: mengoptimumkan kod, menambah instrumentasi atau bahkan melaksanakan ciri bahasa baharu.

Satu penggunaan manipulasi AST yang sangat menarik ialah mencipta bahasa khusus domain (DSL). Kita boleh menghuraikan sintaks tersuai menjadi AST, mengubahnya menjadi Python biasa, dan kemudian melaksanakannya. Ini membolehkan kami mencipta bahasa yang disesuaikan dengan masalah tertentu sambil memanfaatkan kuasa penuh Python.

Sebagai contoh, kita boleh mencipta DSL matematik mudah:

import ast

class MathTransformer(ast.NodeTransformer):
    def visit_BinOp(self, node):
        if isinstance(node.op, ast.Add):
            return ast.Call(
                func=ast.Name(id='add', ctx=ast.Load()),
                args=[self.visit(node.left), self.visit(node.right)],
                keywords=[]
            )
        return node

def parse_math(expr):
    tree = ast.parse(expr)
    transformer = MathTransformer()
    modified_tree = transformer.visit(tree)
    return ast.fix_missing_locations(modified_tree)

def add(a, b):
    print(f"Adding {a} and {b}")
    return a + b

exec(compile(parse_math("result = 2 + 3 + 4"), '<string>', 'exec'))
print(result)
Salin selepas log masuk
Salin selepas log masuk

Ini mengubah operasi tambah kepada panggilan fungsi, membolehkan kami menambah gelagat tersuai (seperti pengelogan) pada operasi matematik asas.

Satu lagi teknik yang berkuasa ialah manipulasi bytecode. Python menyusun kod sumber kepada bytecode sebelum melaksanakannya. Dengan memanipulasi kod bait ini, kami boleh mencapai pengoptimuman atau pengubahsuaian yang sukar atau mustahil pada peringkat kod sumber.

Berikut ialah contoh mudah yang mengubah suai fungsi untuk mengira berapa kali ia dipanggil:

import types

def count_calls(func):
    code = func.__code__
    constants = list(code.co_consts)
    constants.append(0)  # Add a new constant for our counter
    counter_index = len(constants) - 1

    # Create new bytecode
    new_code = bytes([
        101, counter_index,  # LOAD_CONST counter
        100, 1,              # LOAD_CONST 1
        23,                  # BINARY_ADD
        125, counter_index,  # STORE_FAST counter
    ]) + code.co_code

    # Create a new code object with our modified bytecode
    new_code_obj = types.CodeType(
        code.co_argcount, code.co_kwonlyargcount, code.co_nlocals,
        code.co_stacksize + 1, code.co_flags, new_code, tuple(constants),
        code.co_names, code.co_varnames, code.co_filename, code.co_name,
        code.co_firstlineno, code.co_lnotab
    )

    return types.FunctionType(new_code_obj, func.__globals__, func.__name__, func.__defaults__, func.__closure__)

@count_calls
def hello():
    print("Hello, world!")

hello()
hello()
print(hello.__code__.co_consts[-1])  # Print the call count
Salin selepas log masuk

Ini mengubah suai kod bait fungsi untuk menambah pembilang setiap kali ia dipanggil. Ia agak tahap rendah, tetapi ia membenarkan beberapa pengoptimuman dan pengubahsuaian yang sangat hebat.

Satu bidang di mana metaprogramming benar-benar bersinar adalah dalam mencipta algoritma penyesuaian. Kita boleh menulis kod yang menganalisis prestasinya sendiri dan menulis semula dirinya untuk menjadi lebih cekap. Sebagai contoh, kita boleh mencipta fungsi pengisihan yang mencuba algoritma yang berbeza dan memilih yang terpantas untuk data semasa:

code = f"def greet(name):\n    print(f'Hello, {{name}}!')"
exec(code)
greet("Alice")
Salin selepas log masuk
Salin selepas log masuk

Penyusun ini akan menyesuaikan diri secara automatik untuk menggunakan algoritma terpantas untuk data yang dilihatnya.

Metaprogramming juga boleh menjadi sangat berguna untuk ujian dan penyahpepijatan. Kami boleh menggunakannya untuk menjana kes ujian secara automatik, mengejek objek atau menambah instrumentasi pada kod kami.

Berikut ialah contoh mudah yang menjana kes ujian secara automatik untuk sesuatu fungsi:

import ast

def add_logging(node):
    if isinstance(node, ast.FunctionDef):
        log_stmt = ast.Expr(ast.Call(
            func=ast.Attribute(
                value=ast.Name(id='print', ctx=ast.Load()),
                attr='__call__',
                ctx=ast.Load()
            ),
            args=[ast.Str(s=f"Calling {node.name}")],
            keywords=[]
        ))
        node.body.insert(0, log_stmt)
    return node

tree = ast.parse("def hello(): print('Hello, world!')")
modified_tree = ast.fix_missing_locations(ast.NodeTransformer().visit(tree))
exec(compile(modified_tree, '<string>', 'exec'))
hello()
Salin selepas log masuk
Salin selepas log masuk

Ini menjana kes ujian rawak untuk fungsi tambah kami. Kami boleh melanjutkan ini untuk menganalisis AST fungsi dan menjana lebih banyak kes ujian disasarkan.

Salah satu aspek yang paling berkuasa dalam pengaturcaraan meta ialah keupayaannya untuk mengurangkan kod boilerplate. Kami boleh menulis kod yang menulis kod, mengautomasikan tugasan berulang dan memastikan pangkalan kod kami KERING (Jangan Ulangi Sendiri).

Sebagai contoh, kami boleh mengautomasikan penciptaan kelas data:

import ast

class MathTransformer(ast.NodeTransformer):
    def visit_BinOp(self, node):
        if isinstance(node.op, ast.Add):
            return ast.Call(
                func=ast.Name(id='add', ctx=ast.Load()),
                args=[self.visit(node.left), self.visit(node.right)],
                keywords=[]
            )
        return node

def parse_math(expr):
    tree = ast.parse(expr)
    transformer = MathTransformer()
    modified_tree = transformer.visit(tree)
    return ast.fix_missing_locations(modified_tree)

def add(a, b):
    print(f"Adding {a} and {b}")
    return a + b

exec(compile(parse_math("result = 2 + 3 + 4"), '<string>', 'exec'))
print(result)
Salin selepas log masuk
Salin selepas log masuk

Ini mencipta kelas baharu dengan medan dan pembayang jenis yang ditentukan. Kami boleh melanjutkan ini untuk menambah kaedah, sifat atau ciri kelas lain.

Metaprogramming bukan hanya tentang menulis kod yang menulis kod. Ini mengenai mencipta perisian yang lebih fleksibel, boleh disesuaikan dan berkuasa. Ia membolehkan kami mencipta rangka kerja yang boleh menyesuaikan diri dengan kes penggunaan yang berbeza, menjana kod yang dioptimumkan untuk senario tertentu dan mencipta bahasa khusus domain yang menjadikan tugasan rumit menjadi mudah.

Namun, dengan kuasa yang besar datang tanggungjawab yang besar. Metaprogramming boleh menjadikan kod lebih sukar untuk difahami dan nyahpepijat jika tidak digunakan dengan berhati-hati. Adalah penting untuk mendokumentasikan kod pengaturcaraan meta dengan teliti dan menggunakannya dengan bijak.

Kesimpulannya, pengaturcaraan meta dalam Python membuka dunia kemungkinan. Sama ada anda mengoptimumkan prestasi, mengurangkan boilerplate, mencipta DSL atau membina algoritma penyesuaian, teknik pengaturcaraan meta seperti penjanaan kod dan manipulasi AST ialah alat yang berkuasa dalam kit alat Python anda. Mereka membenarkan anda menulis kod yang melampaui biasa, mencipta perisian yang boleh menganalisis, mengubah suai dan memperbaiki dirinya sendiri. Semasa anda meneroka teknik ini, anda akan menemui cara baharu untuk menjadikan kod Python anda lebih fleksibel, cekap dan berkuasa berbanding sebelum ini.


Ciptaan Kami

Pastikan anda melihat ciptaan kami:

Pusat Pelabur | Hidup Pintar | Epos & Gema | Misteri Membingungkan | Hindutva | Pembangunan Elit | Sekolah JS


Kami berada di Medium

Tech Koala Insights | Dunia Epok & Gema | Medium Pusat Pelabur | Medium Misteri Membingungkan | Sains & Zaman Sederhana | Hindutva Moden

Atas ialah kandungan terperinci Menguasai Pengaturcaraan Meta Ajaib Python: Kod yang Menulis Sendiri. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
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

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

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Bagaimana untuk menyelesaikan masalah kebenaran yang dihadapi semasa melihat versi Python di Terminal Linux? Bagaimana untuk menyelesaikan masalah kebenaran yang dihadapi semasa melihat versi Python di Terminal Linux? Apr 01, 2025 pm 05:09 PM

Penyelesaian kepada Isu Kebenaran Semasa Melihat Versi Python di Terminal Linux Apabila anda cuba melihat versi Python di Terminal Linux, masukkan Python ...

Bagaimana untuk mengelakkan dikesan oleh penyemak imbas apabila menggunakan fiddler di mana-mana untuk membaca lelaki-dalam-tengah? Bagaimana untuk mengelakkan dikesan oleh penyemak imbas apabila menggunakan fiddler di mana-mana untuk membaca lelaki-dalam-tengah? Apr 02, 2025 am 07:15 AM

Cara mengelakkan dikesan semasa menggunakan fiddlerevery di mana untuk bacaan lelaki-dalam-pertengahan apabila anda menggunakan fiddlerevery di mana ...

Bagaimana cara menyalin seluruh lajur satu data ke dalam data data lain dengan struktur yang berbeza di Python? Bagaimana cara menyalin seluruh lajur satu data ke dalam data data lain dengan struktur yang berbeza di Python? Apr 01, 2025 pm 11:15 PM

Apabila menggunakan Perpustakaan Pandas Python, bagaimana untuk menyalin seluruh lajur antara dua data data dengan struktur yang berbeza adalah masalah biasa. Katakan kita mempunyai dua DAT ...

Bagaimanakah uvicorn terus mendengar permintaan http tanpa serving_forever ()? Bagaimanakah uvicorn terus mendengar permintaan http tanpa serving_forever ()? Apr 01, 2025 pm 10:51 PM

Bagaimanakah Uvicorn terus mendengar permintaan HTTP? Uvicorn adalah pelayan web ringan berdasarkan ASGI. Salah satu fungsi terasnya ialah mendengar permintaan HTTP dan teruskan ...

Bagaimana Mengajar Asas Pengaturcaraan Pemula Komputer Dalam Kaedah Projek dan Masalah Dikemukakan Dalam masa 10 Jam? Bagaimana Mengajar Asas Pengaturcaraan Pemula Komputer Dalam Kaedah Projek dan Masalah Dikemukakan Dalam masa 10 Jam? Apr 02, 2025 am 07:18 AM

Bagaimana Mengajar Asas Pengaturcaraan Pemula Komputer Dalam masa 10 jam? Sekiranya anda hanya mempunyai 10 jam untuk mengajar pemula komputer beberapa pengetahuan pengaturcaraan, apa yang akan anda pilih untuk mengajar ...

Bagaimana untuk mendapatkan data berita yang melangkaui mekanisme anti-crawler Investing.com? Bagaimana untuk mendapatkan data berita yang melangkaui mekanisme anti-crawler Investing.com? Apr 02, 2025 am 07:03 AM

Memahami Strategi Anti-Crawling of Investing.com Ramai orang sering cuba merangkak data berita dari Investing.com (https://cn.investing.com/news/latest-news) ...

See all articles