Misalkan saya telah menulis seorang dekorator yang melakukan sesuatu yang sangat umum. Misalnya, ini mungkin mengubah semua argumen ke tipe tertentu, melakukan logging, mengimplementasikan memoization, dll.
Berikut ini contohnya:
def args_as_ints(f):
def g(*args, **kwargs):
args = [int(x) for x in args]
kwargs = dict((k, int(v)) for k, v in kwargs.items())
return f(*args, **kwargs)
return g
@args_as_ints
def funny_function(x, y, z=3):
"""Computes x*y + 2*z"""
return x*y + 2*z
>>> funny_function("3", 4.0, z="5")
22
Semuanya baik-baik saja sejauh ini. Namun, ada satu masalah. Fungsi dekorasi tidak menyimpan dokumentasi dari fungsi aslinya:
>>> help(funny_function)
Help on function g in module __main__:
g(*args, **kwargs)
Untungnya, ada solusi:
def args_as_ints(f):
def g(*args, **kwargs):
args = [int(x) for x in args]
kwargs = dict((k, int(v)) for k, v in kwargs.items())
return f(*args, **kwargs)
g.__name__ = f.__name__
g.__doc__ = f.__doc__
return g
@args_as_ints
def funny_function(x, y, z=3):
"""Computes x*y + 2*z"""
return x*y + 2*z
Kali ini, nama fungsi dan dokumentasinya benar:
>>> help(funny_function)
Help on function funny_function in module __main__:
funny_function(*args, **kwargs)
Computes x*y + 2*z
Tapi masih ada masalah: tanda tangan fungsi salah. Informasi "* args, ** kwargs" hampir tidak berguna.
Apa yang harus dilakukan? Saya dapat memikirkan dua solusi sederhana namun cacat:
1 - Sertakan tanda tangan yang benar di docstring:
def funny_function(x, y, z=3):
"""funny_function(x, y, z=3) -- computes x*y + 2*z"""
return x*y + 2*z
Ini buruk karena duplikasi. Tanda tangan tetap tidak akan ditampilkan dengan benar dalam dokumentasi yang dibuat secara otomatis. Sangat mudah untuk memperbarui fungsi dan melupakan tentang mengubah docstring, atau salah ketik. [ Dan ya, saya menyadari fakta bahwa docstring sudah menduplikasi badan fungsi. Harap abaikan ini; funny_function hanyalah contoh acak. ]
2 - Tidak menggunakan dekorator, atau menggunakan dekorator tujuan khusus untuk setiap tanda tangan tertentu:
def funny_functions_decorator(f):
def g(x, y, z=3):
return f(int(x), int(y), z=int(z))
g.__name__ = f.__name__
g.__doc__ = f.__doc__
return g
Ini berfungsi dengan baik untuk sekumpulan fungsi yang memiliki tanda tangan identik, tetapi tidak berguna secara umum. Seperti yang saya katakan di awal, saya ingin dapat menggunakan dekorator secara umum.
Saya mencari solusi yang sepenuhnya umum, dan otomatis.
Jadi pertanyaannya adalah: apakah ada cara untuk mengedit tanda tangan fungsi yang didekorasi setelah dibuat?
Jika tidak, dapatkah saya menulis dekorator yang mengekstrak tanda tangan fungsi dan menggunakan informasi itu daripada "* kwargs, ** kwargs" saat membuat fungsi yang didekorasi? Bagaimana cara mengekstrak informasi itu? Bagaimana saya harus membangun fungsi yang didekorasi - dengan exec?
Ada pendekatan lain?
inspect.Signature
ditambahkan untuk berurusan dengan fungsi dekorasi.