Çok genel bir şey yapan bir dekoratör yazdığımı varsayalım. Örneğin, tüm argümanları belirli bir türe dönüştürebilir, günlüğe kaydetme yapabilir, notlandırma uygulayabilir, vb.
İşte bir örnek:
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
Şimdiye kadar her şey yolunda. Ancak bir sorun var. Dekore edilmiş işlev, orijinal işlevin belgelerini korumaz:
>>> help(funny_function)
Help on function g in module __main__:
g(*args, **kwargs)
Neyse ki, bir çözüm var:
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
Bu sefer işlev adı ve belgeler doğrudur:
>>> help(funny_function)
Help on function funny_function in module __main__:
funny_function(*args, **kwargs)
Computes x*y + 2*z
Ancak yine de bir sorun var: işlev imzası yanlış. "* Args, ** kwargs" bilgisi neredeyse yararsızdır.
Ne yapalım? İki basit ama kusurlu çözüm düşünebilirim:
1 - Doküman dizisine doğru imzayı ekleyin:
def funny_function(x, y, z=3):
"""funny_function(x, y, z=3) -- computes x*y + 2*z"""
return x*y + 2*z
Bu, çoğaltma nedeniyle kötü. İmza, otomatik olarak oluşturulan belgelerde yine düzgün şekilde gösterilmeyecektir. İşlevi güncellemek ve belge dizesini değiştirmeyi unutmak veya bir yazım hatası yapmak kolaydır. [ Ve evet, doktrinin zaten işlev gövdesini kopyaladığı gerçeğinin farkındayım. Lütfen bunu dikkate almayın; funny_function sadece rastgele bir örnektir. ]
2 - Her özel imza için bir dekoratör veya özel amaçlı bir dekoratör kullanmayın:
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
Bu, aynı imzaya sahip bir dizi işlev için iyi çalışır, ancak genel olarak işe yaramaz. Başlangıçta da söylediğim gibi, dekoratörleri tamamen genel bir şekilde kullanabilmek istiyorum.
Tamamen genel ve otomatik bir çözüm arıyorum.
Öyleyse soru şu: dekore edilmiş işlev imzasını oluşturulduktan sonra düzenlemenin bir yolu var mı?
Aksi takdirde, dekore edilmiş işlevi oluştururken işlev imzasını çıkaran ve bu bilgileri "* kwargs, ** kwargs" yerine kullanan bir dekoratör yazabilir miyim? Bu bilgiyi nasıl çıkarırım? Exec ile dekore edilmiş işlevi nasıl oluşturmalıyım?
Başka yaklaşım var mı?
inspect.Signature
Süslü işlevlerle uğraşmaya neyin eklendiğini az çok merak ediyordum .