2013-03-25 13 views
5

Bu dekoratör neden çalışmayan bir parametreyle çalışıyor?Python'da dekoratöre parametre aktarma

def decAny(f0): 
    def wrapper(s0): 
     return "<%s> %s </%s>" % (any, f0(), any) 
    return wrapper 

@decAny('xxx') 
def test2(): 
    return 'test1XML' 

print(test2()) 

hep onu işleme yerine) sarmalayıcı (iç dönüş dize yürütmek ve

+1

bu konuda Şöyle düşünün 'test2'yi dekore etmek için decAny (' xxx ') 'diyorsunuz. Ama "decAny" bir işlev alır, 'f0', bir dize değil. Yani açıkça belli bir noktada, 'f0()' 'xxx'' adını vermeye çalışacaktır. – abarnert

+0

Tamam, ama hiçbir parametresi olmayan bir dekoratörde olduğu gibi, derleyici, ilk parametrenin istemci işlevi olduğunu neden varsaymıyor ... – ZEE

+1

Bu bir parametre meselesi değil. Eğer @ decAny' varsa, bu sadece decAny'yi bir dekoratör olarak kullanıyor. Ama eğer @decAny() 'e sahipseniz," decAny "yi dekorasyona geçmeden önce, '@decAny (' xxx ')' olduğu gibi çağırırsınız. (Aynen fonksiyonlar olarak değerleri iletmek, onları çağırmak yerine değişkenler, vb. Depolamak gibi.) – abarnert

cevap

13

Dekoratörler fonksiyonlardır sonuç dizesini döndürmeye çalışıyor "str değil çağrılabilir" diyerek bana bir hata verir Bu dönen işlevler. "Bir parametreyi dekoratöre geçirirken" aslında yaptığınız şey bir dekoratör döndüren bir işlevi çağırmaktır. Yani decAny(), bir işlevi döndüren bir işlevi döndüren bir işlev olmalıdır.

Böyle görünecektir:

import functools 

def decAny(tag): 
    def dec(f0): 
     @functools.wraps(f0) 
     def wrapper(*args, **kwargs): 
      return "<%s> %s </%s>" % (tag, f0(*args, **kwargs), tag) 
     return wrapper 
    return dec 

@decAny('xxx') 
def test2(): 
    return 'test1XML' 

Örnek: asıldığın sorunla sabitleme ek olarak ben de biraz *args ekleyerek kod geliştirilmiş

>>> print(test2()) 
<xxx> test1XML </xxx> 

Not olduğunu

ve Sarma işlevine argümanlar olarak **kwargs ve dekoratörün iç kısmına f0 çağrılarını iletme. Bu, herhangi bir sayıdaki konumsal veya adlandırılmış argümanı kabul eden bir işlevi süsleyebilmenizi sağlar ve yine de doğru şekilde çalışmaya devam eder.

Burada yaklaşık functools.wraps() kadar okuyabilir:
http://docs.python.org/2/library/functools.html#functools.wraps

+0

[PEP 318] (http://www.python.org/dev/peps/pep-0318/) bu modeli gösteren örnekleri içerir (type özniteliklerini veya arabirimlerini zorlar, 'synize' vb.). – abarnert

+1

Eğer '* args, ** kwargs' ekleyecekseniz kodunu (nedenini açıklamaksızın) iyileştirmek istiyorsanız, muhtemelen' functools.wraps'ı da eklemek istersiniz. – abarnert

+0

@abarnert Öneri için teşekkürler, 'functools.wraps' ve bazı ek açıklamalar ekledi. –

1

"Mark Lutz - Öğrenme Python" iyi bir örnek vardır kitap: hatta _get_ Senden önce:

def timer(label=''): 
    def decorator(func): 
     def onCall(*args): # Multilevel state retention: 
      ...    # args passed to function 
      func(*args)  # func retained in enclosing scope 
      print(label, ... # label retained in enclosing scope 
     return onCall 
    return decorator   # Returns the actual decorator 

@timer('==>')    # Like listcomp = timer('==>')(listcomp) 
def listcomp(N): ...   # listcomp is rebound to new onCall 

listcomp(...)    # Really calls onCall