2009-12-27 15 views
23

Sono in corso per imparare Python. Spero che qualcuno mi punti per correggere il modo.
Questo è quello che mi piacerebbe fare qui di seguito:Come posso passare una variabile in un decoratore all'argomento della funzione in una funzione decorata?

def decorate(function): 
    def wrap_function(*args, **kwargs): 
     str = 'Hello!' # This is what I want 
     return function(*args, **kwargs) 
    return wrap_function 

@decorate 
def print_message(): 
    # I'd like to pass 'str' as mentioned above 
    # to any functions' argument like below: 
    print(str) # 'str' is same as above 

Qualche idea? Grazie in anticipo.

risposta

30

Non è possibile passarlo come nome proprio, ma è possibile aggiungerlo alle parole chiave.

def decorate(function): 
    def wrap_function(*args, **kwargs): 
     kwargs['str'] = 'Hello!' 
     return function(*args, **kwargs) 
    return wrap_function 

@decorate 
def print_message(*args, **kwargs): 
    print(kwargs['str']) 

In alternativa è possibile nominare un proprio argomento:

def decorate(function): 
    def wrap_function(*args, **kwargs): 
     str = 'Hello!' 
     return function(str, *args, **kwargs) 
    return wrap_function 

@decorate 
def print_message(str, *args, **kwargs): 
    print(str) 

metodo Classe:

def decorate(function): 
    def wrap_function(*args, **kwargs): 
     str = 'Hello!' 
     args.insert(1, str) 
     return function(*args, **kwargs) 
    return wrap_function 

class Printer: 
    @decorate 
    def print_message(self, str, *args, **kwargs): 
     print(str) 
+4

Si noti che la prima soluzione viene anche ottenuta usando 'functools.partial()' (ma solo dalla versione 2.6). Lo stesso modulo offre anche la funzione 'wraps()' che può essere usata con i decoratori per mantenere il nome e il doc della funzione originale. – RedGlyph

+0

@RedGlyph: perché usare 'functools.partial()' solo dalla versione 2.6? la documentazione non dice nulla a riguardo tranne che il modulo functools è nuovo in pyhton 2.5. –

+0

Grazie a Tor Valamo. La soluzione alternativa è chiara per me. Ma che dire se la funzione decorata è un metodo di istanza? L'argomento del metodo di istanza dovrebbe essere qualcosa come: 'def print_message (str, self, * args, ** kwargs):' È corretto? Grazie ancora. – Japboy

5

Se si desidera che l'argomento sia "opzionalmente-iniezione", solo nel caso in cui la funzione di in realtà prende, utilizzare qualcosa del genere:

import inspect 

def decorate(func): 
    def wrap_and_call(*args, **kwargs): 
     if 'str' in inspect.getargspec(func).args: 
      kwargs['str'] = 'Hello!' 
     return func(*args, **kwargs) 
    return wrap_and_call 

@decorate 
def func1(str): 
    print "Works! - " + str 

@decorate 
def func2(): 
    print "Should work, also." 
Problemi correlati