[Tutor] Python decorator to ensure that kwargs are correct

Rich Lovely roadierich at googlemail.com
Sat Sep 19 01:58:03 CEST 2009


2009/9/18 Manuel de la  Pena <mandel at themacaque.com>:
> Hello,
>
>
> I have done a decorator that I used to ensure that the keyword arguments
> passed to a constructor are the correct/expected ones. The code is the
> following:
>
> from functools import wraps
>
> def keyargs_check(keywords):
> """
> This decorator ensures that the keys passed in kwargs are the onces that
> are specified in the passed tuple. When applied this decorate will
> check the keywords and will throw an exception if the developer used
> one that is not recognized.
>
> @type keywords: tuple
> @param keywords: A tuple with all the keywords recognized by the function.
> """
>
> def wrap(f):
>    @wraps(f)
>    def newFunction(*args, **kw):
>        # we are going to add an extra check in kw
>        for current_key in kw.keys():
>            if not current_key in keywords:
>                raise ValueError(
>                    "The key {0} is a not recognized parameters by {1}.".format(
>                        current_key, f.__name__))
>        return f(*args, **kw)
>    return newFunction
> return wrap
>
> An example use of this decorator would be the following:
>
> class Person(object):
>
> @keyargs_check(("name", "surname", "age"))
> def __init__(self, **kwargs):
>    # perform init according to args
>
> Using the above code if the developer passes a key args like "blah" it
> will throw an exception. Unfortunately my implementation has a major
> problem with inheritance, if I define the following:
>
> class PersonTest(Person):
>
> @keyargs_check(("test"))
> def __init__(self, **kwargs):
>    Person.__init__(self,**kwargs)
>
> Because I'm passing kwargs to the super class init method, I'm going to
> get an exception because "test" is not in the tuple passed to the
> decorator of the super class. Is there a way to let the decorator used
> in the super class to know about the extra keywords? or event better, is
> there a standard way to achieve what I want?
>
>
> Thanks in advance for any help or input,
>
> kr,
>
> Manuel
>
>
>
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> http://mail.python.org/mailman/listinfo/tutor
>

Is there any specific reason you need to use **kwargs?

If you omit it from function definitions, you can use normal argument format:
>>> class Demo(object):
... 	def __init__(self, name="", surname="", age=0):
... 		print name, surname, age
... 		
>>> Demo(name='Rich', surname=Lovely, age=24)
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
NameError: name 'Lovely' is not defined
>>> Demo(name='Rich', surname='Lovely', age=24)
Rich Lovely 24
<__main__.Demo object at 0x00F75230>
>>> Demo(notAValidParam='foo')
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
TypeError: __init__() got an unexpected keyword argument 'notAValidParam'
>>>

It does of course break if you use positional arguments, but part of
the theory behind python is that we're all consenting adults, and
should know better than to do things that break existing code.  It is
for this reason that you can overwrite builtins like range or list
without the interpretter moaning.
-- 
Rich "Roadie Rich" Lovely

There are 10 types of people in the world: those who know binary,
those who do not, and those who are off by one.


More information about the Tutor mailing list