2010-03-30 3 views
4

Je suis en train d'installer des décorateurs pour que je puisse faire quelque chose comme:Comment gérer l'argument « auto » avec décorateurs Python

class Ball(object): 
    def __init__(self, owner): 
     self.owner = owner 

class Example(CommandSource): 
    @command 
    @when(lambda self, ball: ball.owner == self) 
    def throwBall(self, ball): 
     # code to throw the ball 
     pass 

e = Example() 
ball = Ball(e) 
commands = e.listCommands(ball) # commands = [ 'throwBall' ] 

Cela ne fonctionne pas actuellement, comme lorsque le lambda de validation est appelée, il n'y a pas d'auto-argument passé.

Maintenant, quelque chose comme ça fonctionne très bien:

class Example(CommandSource): 
    @command 
    @when(lambda ball: ball.is_round) 
    def throwBall(self, ball): 
     pass 

Mais cela ne fonctionne pas non plus:

class Example(CommandSource): 
    def verify_owner(self, ball): 
     return ball.owner == self 

    @command 
    @when(verify_owner) 
    def throwBall(self, ball): 
     pass 

Le but est d'être en mesure de marquer des méthodes dans une classe comme une « commande » , et le obtenir une liste de commandes qui sont valides pour exécuter. En fait, l'exécution de la méthode est inchangée. Je voudrais utiliser des décorateurs ici, car il semble que la façon la moins klunky de faire cela. En effet j'essaye d'installer un peu de DSL en utilisant Python.

Mais j'ai des difficultés, surtout avec l'argument self. Voici mon implémentation actuelle de command, when et CommandSource:

def command(cmd): 
    if getattr(cmd, 'command', False): return cmd 

    def wrapper(*args, **kwargs): 
     return cmd(*args, **kwargs) 

    wrapper.validators = [] 
    wrapper.command = True 

    return wrapper 

def when(predicate): 
    def createCommand(cmd):  
     newcmd = command(cmd) 
     newcmd.validators.append(predicate) 
     return newcmd 
    return createCommand 

class CommandSource(object): 
    def listCommands(self, *args, **kwargs): 
     commands = [] 
     for command in dir(self.__class__): 
      func = getattr(self, command, None) 

      if func == None or getattr(func, 'command', False) == False: 
       continue 
      valid = True 
      for validator in func.validators: 
       if not validator(*args, **kwargs): 
        valid = False 
        break 
      if valid: 
       commands.append(command) 
     return commands 

Répondre

2

Changer votre CommandSource comme suit:

class CommandSource(object): 

    def listCommands(self, *args, **kwargs): 
     commands = [] 
     for command in dir(self.__class__): 
      func = getattr(self, command, None) 
      if func == None or getattr(func, 'command', False) == False: 
       continue 
      for validator in func.validators: 
       if not validator(self, *args, **kwargs): 
        break 
      else: 
       commands.append(command) 
     return commands 

et utilisez votre premier code.

+1

Grande, qui fonctionne aussi grâce à l'aide de la '' else' pour la boucle for' intérieure. –

1

Vous devez passer une référence d'instance à votre fonction validator:

for validator in func.validators: 
    if not validator(self, *args, **kwargs): 
     valid = False 
     break 
Questions connexes