Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Very confused about decorators

I thought I understood decorators but not anymore. Do decorators only work when the function is created?

I wanted to create a series of functions that all have a required argument called 'ticket_params' that is a dictionary. and then decorate them with something like @param_checker(['req_param_1', 'req_param_2']) and then if 'req_param_1' and 'req_param_2' aren't in the dictionary, raise a custom Exception subclass. Am I thinking of this all wrong?

It would be something like this in the calling code:

@param_checker(['req_param_1', 'req_param_2'])
def my_decorated_function(params):
    # do stuff

params = {'req_param_1': 'Some Value'}
my_decorated_function(params)

# exception would be raised here from decorator.
like image 528
orokusaki Avatar asked Mar 16 '26 12:03

orokusaki


2 Answers

A decorator is applied immediately after the def statement; the equivalence is:

@param_checker(['req_param_1', 'req_param_2'])
def my_decorated_function(params):
    # do stuff

is exactly the same thing as:

def my_decorated_function(params):
    # do stuff
my_decorated_function = param_checker(['req_param_1', 'req_param_2'])(my_decorated_function)

So the job of param_checker is to return a function that takes as its argument the function to be decorated and returns yet another function which does what you require. OK so far?

Edit: so, here's one implementation...:

import functools

def param_checker(reqs):
  reqs = set(reqs)
  def middling(f):
    @functools.wraps(f)
    def wrapper(params):
      missing = reqs.difference(params)
      if missing:
        raise TypeError('Missing parms: %s' % ', '.join(sorted(missing)))
      return f(params)
    return wrapper
  return middling
like image 95
Alex Martelli Avatar answered Mar 19 '26 02:03

Alex Martelli


Decorators are only called once on a function, that is, when the def statement is parsed like so:

@mydecorator
def myfunction(): ...

I assume you mean something like that:

class param_checker:
  def __init__(self, l):
    self.l = l

  def __call__(self, functionToBeDecorated):
    def wrapper(*args, **kwargs):
      if any(necessary not in kwargs["ticket_params"] for necessary in self.l):
        raise MyCustomException
      return functionToBeDecorated(*args, **kwargs)

    return wrapper

Please tell me if you don't understand that ;)

like image 23
AndiDog Avatar answered Mar 19 '26 01:03

AndiDog



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!