2010-03-30 55 views
4

我試圖建立一些裝飾,這樣我可以這樣做「自我」的說法:如何處理與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' ] 

目前這是不行的,因爲當驗證拉姆達被調用時,沒有通過自我論證。

現在是這樣的正常工作:

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

但這也不起作用:

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

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

的目的是爲了能夠標記在一個類中的方法爲「命令」 ,並獲取有效運行的命令列表。實際運行該方法是不變的。我想在這裏使用裝飾器,因爲它似乎是最簡單的方法來做到這一點。實際上,我試圖使用Python設置一個小的DSL。

但我有困難,特別是與self的論點。這是我目前執行的commandwhenCommandSource

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 

回答

2

更改CommandSource如下:

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 

,並使用你的第一個代碼。

+1

大,這樣的作品,也感謝您使用了'else'的內部'for'循環。 – 2010-03-30 16:59:45

1

你需要一個實例引用傳遞到您的validator功能:

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