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:
... 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:
x=1, y=2, args=(3, 4)
kwargs['key'] is None and kwargs['word'] is 'parrot' 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:
x=1, y=2, args=(3,)
kwargs['key'] is None and kwargs['word'] is 'spam' 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:
... 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!)