Как обрабатывать аргумент «self» с помощью декораторов Python - PullRequest
4 голосов
/ 30 марта 2010

Я пытаюсь настроить некоторые декораторы так, чтобы я мог сделать что-то вроде:

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' ]

В настоящее время это не работает, так как при вызове лямбда-проверки аргумент self не передается.

Теперь что-то вроде этого работает нормально:

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

Цель состоит в том, чтобы иметь возможность пометить методы в классе как «команду» и получить список команд, которые допустимы для выполнения. На самом деле запуск метода не изменился. Я хотел бы использовать декораторы здесь, так как это кажется наименее хитрым способом сделать это. По сути, я пытаюсь настроить немного DSL, используя Python.

Но у меня трудности, особенно с аргументом self. Вот моя текущая реализация command, when и 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

Ответы [ 2 ]

2 голосов
/ 30 марта 2010

Измените 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 голос
/ 30 марта 2010

Вам необходимо передать ссылку на экземпляр вашей функции validator:

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