web-dev-qa-db-fra.com

Utilisation de Python Decorator avec ou sans parenthèses

Quelle est la différence dans Python lorsque vous utilisez le même décorateur avec ou sans parenthèses ? Par exemple:

Sans parenthèses

@someDecorator
def someMethod():
    pass

Avec des parenthèses

@someDecorator()
def someMethod():
    pass
41
BendEg

someDecorator dans le premier extrait de code est un décorateur régulier:

@someDecorator
def someMethod():
    pass

est équivalent à 

someMethod = someDecorator(someMethod)

Par ailleurs, someDecorator dans le deuxième extrait de code est un appelable qui renvoie un décorateur:

@someDecorator()
def someMethod():
    pass

est équivalent à

someMethod = someDecorator()(someMethod)

Comme l'a souligné Duncan dans ses commentaires, certains décorateurs sont conçus pour fonctionner dans les deux sens. Voici une jolie implémentation de base d'un tel décorateur:

def someDecorator(arg=None):
    def decorator(func):
        def wrapper(*a, **ka):
            return func(*a, **ka)
        return wrapper

    if callable(arg):
        return decorator(arg) # return 'wrapper'
    else:
        return decorator # ... or 'decorator'

pytest.fixture est un exemple plus complexe.

46
vaultah

Certains codes fonctionnant réellement où vous utilisez le décorateur arg inside:

def someDecorator(arg=None):
    def decorator(func):
        def wrapper(*a, **ka):
            if not callable(arg):
                print (arg)
                return func(*a, **ka)
            else:
                return 'xxxxx'
        return wrapper

    if callable(arg):
        return decorator(arg) # return 'wrapper'
    else:
        return decorator # ... or 'decorator'

@someDecorator(arg=1)
def my_func():
    print('aaa')

@someDecorator
def my_func1():
    print('bbb')

if __== "__main__":
    my_func()
    my_func1()

La sortie est:

1
aaa
0