How to handle the self argument with Python decorators

I am trying to set up some decorators so that I can do something like:

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

This does not currently work, since the argument itself is not passed when calling lambda validation.

Now something like this works great:

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

But this also does not work:

 class Example(CommandSource): def verify_owner(self, ball): return ball.owner == self @command @when(verify_owner) def throwBall(self, ball): pass 

The goal is to be able to mark methods in the class as a "command" and get a list of commands that are valid to run. Actually, the method launch has not changed. I would like to use decorators here, as this is apparently the least klunky way to do this. Essentially, I'm trying to set up a bit of DSL using Python.

But I'm having difficulties, especially with the self argument. Here is my current implementation of command , when and 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 
+4
source share
2 answers

Modify the CommandSource as follows:

 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 

and use your very first code.

+2
source

You need to pass a link to an instance of your validator function:

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

Source: https://habr.com/ru/post/1305569/


All Articles