2010-10-17 17 views
3

J'essaie d'obtenir une variable locale d'un décorateur. Un exemple:Obtention de variables locales de la fonction

def needs_privilege(privilege, project=None): 
    """Check whether the logged-in user is authorised based on the 
    given privilege 

    @type privilege: Privilege object, id, or str 
    @param privilege: The requested privilege""" 

    def validate(func, self, *args, **kwargs): 
     """Validator of needs_privillige""" 
     try: check(self.user, privilege, project) 
     except AccessDenied: 
      return abort(status_code=401) 
     else: 
      return func(self, *args, **kwargs) 

    return decorator(validate) 

Après la décoration d'une fonction, comme ceci:

@needs_privilege("some_privilege") 
def some_function(): 
    pass 

Je voudrais récupérer la variable 'privilige' (qui valide() utilise) à partir une_fonction. Après avoir cherché plus d'une heure, je me sens plutôt perdu. Est-ce possible?

Modifier: Permettez-moi de décrire mon problème un peu plus à fond: puis-je obtenir la chaîne « some_prvilege » sans exécuter une_fonction? Quelque chose comme:

a = getattr(module, 'somefunction') 
print a.decorator_arguments 

? Merci de m'avoir aidé jusqu'à présent!

+1

Plusieurs personnes sont venues avec essentiellement la même réponse, mais ce qui est clair est de savoir si vous avez besoin du package décorateur (avec 'decorator (validate)'). Est-ce une exigence? – snapshoe

+0

Non, ce n'est pas une exigence. Ma question a été répondue dans ce fil (voir ci-dessous). Merci les gars/filles! – Martijn

Répondre

3

Votre décorateur essentiellement vérifier si un utilisateur a l'autorisation d'exécuter une fonction donnée, je ne comprends pas vraiment pourquoi vous souhaitez récupérer (joindre) le privilège à la fonction qui était en train d'être enveloppée mais vous pouvez le faire sans ajouter un autre argument à toutes vos fonctions.

def needs_privilege(privilege, project=None): 
    """Check whether the logged-in user is authorised based on the 
    given privilege 

    @type privilege: Privilege object, id, or str 
    @param privilege: The requested privilege""" 

    def validate(func, self, *args, **kwargs): 
     """Validator of needs_privillige""" 
     try: check(self.user, privilege, project) 
     except AccessDenied: 
      return abort(status_code=401) 
     else: 
      return func(self, *args, **kwargs) 
    validate.privelege = privelege 
    return decorator(validate) 

par la façon dont votre décorateur devrait ressembler à ceci:

def needs_privilege(privilege, project=None): 
    def validate(func): 
     def new_func(self, *args, **kwargs): 
      try: 
       check(self.user, privilege, project) 
      except AccessDenied: 
       return abort(status_code=401) 
      else: 
       return func(self, *args, **kwargs) 
     new_func.privilege = privilege 
     return new_func 
    return validate 
+0

Merci, mais ce n'est pas ce que je cherche, désolé. Je voudrais récupérer 'privilège' sans réellement exécuter la fonction. S'il vous plaît voir mon edit. – Martijn

+0

Mzialla: est ce travail pour vous maintenant :) – mouad

+0

Oui, merci beaucoup! – Martijn

2

Vous pouvez passer comme paramètre:

def needs_privilege(privilege, project=None): 
    """Check whether the logged-in user is authorised based on the 
    given privilege 

    @type privilege: Privilege object, id, or str 
    @param privilege: The requested privilege""" 

    def validate(func, self, *args, **kwargs): 
     """Validator of needs_privillige""" 
     try: check(self.user, privilege, project) 
     except AccessDenied: 
      return abort(status_code=401) 
     else: 
      return func(self, privilege, *args, **kwargs) 

    return decorator(validate) 

@needs_privilege("some_privilege") 
def some_function(privilege): 
    pass 
+0

Merci pour votre réponse! Pas tout à fait ce que je cherche. Je veux passer l'argument à needs_privilege * sans * exécuter la fonction réelle (some_function, dans ce scénario). – Martijn

0

Les fonctions sont des objets qui peuvent avoir des attributs aussi. Vous pouvez définir des attributs dans le décorateur. Voici un exemple:

class TestClass(object): 
    def needs_privilege(privilege, project=None): 
     def wrapper(func): 
      def validate(self, *args, **kwargs): 
       """Validator of needs_privillige""" 
       print 'validator check for %s' % privilege 
       return func(*args, **kwargs) 
      validate.privilege = privilege 
      return validate 

     return wrapper 

    @needs_privilege("foo") 
    def bar(): 
     print "called" 

>>> test.TestClass().bar() 
validator check for foo 
called 
>>> test.TestClass.bar.privilege 
'foo' 
>>> test.TestClass().bar.privilege 
'foo' 
+0

Merci pour votre réponse! Comme je l'ai dit à 'unutbu', il est dommage que je ne puisse choisir qu'une seule réponse! – Martijn

1

Votre problème serait beaucoup plus simple si vous ne l'avez pas besoin du module decorator. Si vous ne strictement pas besoin du module decorator, vous pouvez écrire le décorateur comme celui-ci:

def needs_privilege(privilege, project=None): 
    def validate(func): 
     def _validate(self, *args, **kwargs): 
      return func(self, *args, **kwargs) 
     _validate.decorator_args=(privilege,project) 
     return _validate 
    return validate 

@needs_privilege("some_privilege") 
def some_function(self): 
    pass 

a = some_function 
print(a.decorator_args) 
# ('some_privilege', None) 
+0

+1 J'essayais de trouver un moyen de dire la même chose. Le package décorateur ajoute une couche supplémentaire de complexité au problème. – snapshoe

+0

Merci! C'est dommage que je ne peux choisir qu'une réponse comme solution. – Martijn