2017-05-23 1 views
1

Lors de la décoration d'une fonction, vous pouvez utiliser une méthode @object.method, et vous pouvez utiliser des méthodes d'attributs d'attributs et ainsi de suite @object.attribute.attribute.method. Vous pouvez également passer des arguments supplémentaires au décorateur @function(foo="bar").Fonction appelle dans la décoration de fonction

Cependant, il semble que ces conflits. Quand il y a un appel de fonction dans la chaîne, python semble supposer que c'est le bit où vous passez des arguments au décorateur, et toutes les chaînes après cela sont des SyntaxError.

Y at-il quelque chose qui me manque ici? Une raison de ce comportement ou un moyen de contourner le problème?

Ce code a été écrit pour Python 3.4.

#!/usr/bin/env python3 

class Decorator: 
    def decorate(self, callback): 
     return callback 

_dec = Decorator() 
def findit(): 
    return _dec 

class B: dec = _dec 
class A: bar = B() 
foo = A() 

dec = findit() 
@dec.decorate 
#@findit().decorate 
#Above line is a syntax error 
@foo.bar.dec.decorate #also permitted 
def function(): 
    pass 

Erreur:

File "test.py", line 17 
    @findit().decorate 
      ^
SyntaxError: invalid syntax 
+0

Essayez '@ (findit() décorer.)'. Pourrait être un problème de priorité? –

+0

'@ (findit(). Decorate)' donne une erreur de syntaxe sur le crochet d'ouverture. – AI0867

Répondre

2

The grammar pour les décorateurs est quelque chose comme:

decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE 
decorators: decorator+ 
decorated: decorators (classdef | funcdef | async_funcdef) 

ici dotted_name est (AKA foo, foo.bar.spam etc):

dotted_name: NAME ('.' NAME)* 

De la grammaire, il est clair que la parenthèse ne peut être suivie d'une nouvelle ligne pas une autre dotted_name, par conséquent, il génère une erreur de syntaxe.

Donc, pour résoudre ce problème assurez-vous que l'appel de fonction est toujours à la fin, s'il y a un appel de fonction entre vous devez l'assigner à une variable préalable (prise à partir du code uniquement):

dec = findit() 
@dec.decorate 

pour l'histoire liée à la syntaxe de décorateur vous pouvez passer par ce document: https://wiki.python.org/moin/PythonDecorators

2

Vous avez déjà la solution au sein de votre question. Il suffit d'évaluer findit() avant de l'appliquer comme décorateur:

dec = findit() 
@dec.decorate 
def function(): 
    pass 

Rappelez-vous que la syntaxe @decorator est juste du sucre syntaxique, de sorte que ce qui précède équivaut à:

def function(): 
    pass 

function = findit().decorate(function)