kw param question
kj
no.email at please.post
Tue Aug 4 12:07:34 EDT 2009
In <pan.2009.08.04.04.06.14 at REMOVE.THIS.cybersource.com.au> Steven D'Aprano <steven at REMOVE.THIS.cybersource.com.au> writes:
>On Mon, 03 Aug 2009 19:59:23 +0000, kj wrote:
>> I want to write a decorator that, among other things, returns a function
>> that has one additional keyword parameter, say foo=None.
>>
>> When I try
>>
>> def my_decorator(f):
>> # blah, blah
>> def wrapper(*p, foo=None, **kw):
>> x = f(*p, **kw)
>> if (foo):
>> # blah, blah
>> else
>> # blah blah
>> return wrapper
>>
>> ...i get a syntax error where it says "foo=None". I get similar errors
>> with everything else I've tried.
>>
>> Is is possible to do this in Python?
>Have you tried this under Python 2.6 or 3.0?
>I've run into similar issues, because you can't have keyword-only
>arguments in Python 2.5 :(
>My solution was to create a decorator that faked them. The docstring is
>longer than the decorator itself.
>from functools import wraps
>def keywords(**defaults):
> """Return a decorator which decorates a function to accept keyword
> arguments.
> Python 2.5 and earlier don't allow keyword-only arguments for
> non-builtin functions. The obvious syntax:
> def func(x, *args, key=None, word='parrot'):
> is not permitted. As a work-around, write your function something
> like the following example:
> >>> @keywords(key=None, word='parrot')
> ... def func(x, y=0, *args, **kwargs):
> ... # Inside the function, we can guarantee that kwargs['key'] and
> ... # kwargs['word'] both exist, and no other keys.
> ... print "x=%s, y=%s, args=%s" % (x, y, args)
> ... if kwargs['key'] is None: msg = "kwargs['key'] is None"
> ... else: msg = "kwargs['key'] is something else"
> ... msg += " and kwargs['word'] is %r" % kwargs['word']
> ... print msg
> ...
> When you call func, if you don't provide a keyword-only argument, the
> default will be substituted:
> >>> func(1, 2, 3, 4)
> x=1, y=2, args=(3, 4)
> kwargs['key'] is None and kwargs['word'] is 'parrot'
> >>> func(1)
> x=1, y=0, args=()
> kwargs['key'] is None and kwargs['word'] is 'parrot'
> Naturally you can provide your own values for keyword-only arguments:
> >>> func(1, 2, 3, word='spam')
> x=1, y=2, args=(3,)
> kwargs['key'] is None and kwargs['word'] is 'spam'
> >>> func(1, 2, 3, word='spam', key=len)
> x=1, y=2, args=(3,)
> kwargs['key'] is something else and kwargs['word'] is 'spam'
> If you pass an unexpected keyword argument, TypeError is raised:
> >>> #doctest:+IGNORE_EXCEPTION_DETAIL
> ... func(1, 2, 3, 4, keyword='something')
> Traceback (most recent call last):
> ...
> TypeError: ...
> """
> def decorator(func):
> """Decorate func to allow keyword-only arguments."""
> @wraps(func)
> def f(*args, **kwargs):
> for key in kwargs:
> if key not in defaults:
> raise TypeError(
> "'%s' is an invalid keyword argument for " \
> "this function" % key
> )
> d = defaults.copy()
> d.update(kwargs)
> return func(*args, **d)
> return f
> return decorator
Thanks for this. It's very useful. A lot of stuff for me to chew
on.
kynn
More information about the Python-list
mailing list