kw param question
Steven D'Aprano
steven at REMOVE.THIS.cybersource.com.au
Tue Aug 4 00:06:15 EDT 2009
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
(Copy and pasted from working code, but I make no guarantee that it will
have survived the process in working order!)
--
Steven
More information about the Python-list
mailing list