Ketika mencari dekorator Python seseorang membuat pernyataan, bahwa mereka sekuat macro Lisp (terutama Clojure).
Melihat contoh-contoh yang diberikan dalam PEP 318 bagi saya seolah-olah itu hanya cara mewah untuk menggunakan fungsi-fungsi tingkat tinggi lama yang biasa di Lisp:
def attrs(**kwds):
def decorate(f):
for k in kwds:
setattr(f, k, kwds[k])
return f
return decorate
@attrs(versionadded="2.2",
author="Guido van Rossum")
def mymethod(f):
...
Saya belum melihat kode yang berubah dalam salah satu contoh, seperti dijelaskan dalam Anatomi Makro Clojure . Ditambah lagi, homoikonisitas Python yang hilang dapat membuat transformasi kode menjadi tidak mungkin.
Jadi, bagaimana keduanya membandingkan dan dapatkah Anda mengatakan mereka setara dalam hal apa yang dapat Anda lakukan? Bukti tampaknya menunjukkan hal yang berlawanan.
Sunting: Berdasarkan pada komentar, saya mencari dua hal: perbandingan pada "sekuat" dan "semudah melakukan hal-hal yang luar biasa dengan".
Jawaban:
Sebuah dekorator pada dasarnya hanya fungsi .
Contoh dalam Common Lisp:
Dalam fungsi di atas adalah simbol (yang akan dikembalikan oleh
DEFUN
) dan kami menempatkan atribut pada daftar properti simbol .Sekarang kita dapat menuliskannya di sekitar definisi fungsi:
Jika kita ingin menambahkan sintaksis mewah seperti di Python, kita menulis makro pembaca . Makro pembaca memungkinkan kita untuk memprogram pada tingkat sintaks s-ekspresi:
Kami kemudian dapat menulis:
Pembaca Lisp membaca di atas untuk:
Sekarang kami memiliki bentuk dekorator di Common Lisp.
Menggabungkan macro dan macro pembaca.
Sebenarnya saya akan melakukan terjemahan di atas dalam kode nyata menggunakan makro, bukan fungsi.
Penggunaannya seperti di atas dengan pembaca makro yang sama. Keuntungannya adalah bahwa kompilator Lisp masih melihatnya sebagai apa yang disebut formulir tingkat atas - kompiler file * memperlakukan formulir tingkat atas secara khusus, misalnya menambahkan informasi tentang mereka ke dalam lingkungan waktu kompilasi . Pada contoh di atas kita dapat melihat bahwa makro melihat ke dalam kode sumber dan mengekstrak namanya.
Pembaca Lisp membaca contoh di atas menjadi:
Yang kemudian diperluas makro menjadi:
Makro sangat berbeda dari makro pembaca .
Makro mendapatkan kode sumber lulus, dapat melakukan apa pun yang mereka inginkan dan kemudian mengembalikan kode sumber. Sumber input tidak perlu kode Lisp yang valid. Itu bisa apa saja dan bisa ditulis sama sekali berbeda. Hasilnya harus kode Lisp yang valid. Tetapi jika kode yang dihasilkan menggunakan makro juga, maka sintaks dari kode yang tertanam dalam panggilan makro lagi bisa menjadi sintaks yang berbeda. Contoh sederhana: seseorang dapat menulis makro matematika yang akan menerima semacam sintaksis matematika:
Ekspresi
y = 3 x ^ 2 - 4 x + 3
ini bukan kode Lisp yang valid, tetapi makro misalnya dapat menguraikannya dan mengembalikan kode Lisp yang valid seperti ini:Ada banyak kasus penggunaan makro di Lisp.
sumber
Dalam Python (bahasa) dekorator tidak dapat memodifikasi fungsi, hanya membungkusnya, jadi mereka jelas jauh lebih kuat daripada macro lisp.
Dalam CPython (interpreter) dekorator dapat memodifikasi fungsi karena mereka memiliki akses ke bytecode, tetapi fungsi tersebut dikompilasi terlebih dahulu dan kemudian dapat dipermainkan oleh dekorator, sehingga tidak mungkin untuk mengubah sintaksis, suatu hal lisp-macro -Seivalen perlu dilakukan.
Perhatikan, bahwa lisps modern tidak menggunakan ekspresi-S sebagai bytecode, jadi makro yang bekerja pada daftar ekspresi-S pasti bekerja sebelum kompilasi bytecode seperti yang disebutkan di atas, dengan python dekorator berjalan setelahnya.
sumber
Sangat sulit untuk menggunakan dekorator Python untuk memperkenalkan mekanisme aliran kontrol baru.
Berbatasan-dengan-sepele untuk menggunakan macro Lisp Umum untuk memperkenalkan mekanisme aliran kontrol baru.
Dari sini, mungkin berarti mereka tidak sama ekspresifnya (saya memilih untuk menafsirkan "kuat" sebagai "ekspresif", karena saya berpikir apa yang sebenarnya mereka maksudkan).
sumber
s/quite hard/impossible/
Ini tentu saja berkaitan dengan functionallity, tetapi dari dekorator Python tidak sepele untuk memodifikasi metode yang dipanggil (itu akan menjadi
f
parameter dalam contoh Anda). Untuk memodifikasinya, Anda bisa menjadi gila dengan modul ast ), tetapi Anda akan menyukai beberapa pemrograman yang cukup rumit.Hal-hal di sepanjang garis ini telah dilakukan: periksa paket makropi untuk beberapa contoh yang benar-benar membekas .
sumber
ast
hal -transformasi dalam python tidak sama dengan macro Lisp. Dengan Python, bahasa sumber haruslah Python, dengan Lisp macro bahasa sumber yang diubah oleh makro bisa, secara harfiah, apa saja. Oleh karena itu, metaprogramming Python hanya cocok untuk hal-hal sederhana (seperti AoP), sedangkan metaprogramming Lisp berguna untuk mengimplementasikan kompiler eDSL yang kuat.