kw param question

K

kj

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?

TIA!

kynn
 
A

Albert Hopkins

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.

Not exactly sure what you're trying to do.. but, regular arguments must
be used *before* positional and keyword arguments so the definition:

def wrapper(*p, foo=None, **kw):

is syntactically incorrect whereby the following is correct:

def wrapper(foo=None, *p, **kw):

But if what you are wanting is to actually add 'foo' to kw then I would
do this:

def my_decorator(f):
# blah, blah
def wrapper(*p, **kw):
if 'foo' not in kw:
kw['foo'] = None
x = f(*p, **kw)
if kw['foo']:
# blah blah
else:
# blah blah
return wrapper
 
K

kj

Not exactly sure what you're trying to do..

Yeah, I wasn't too clear. I figured out how to do what I wanted
to do:

def my_decorator(f):
# blah, blah
def wrapper(*p, **kw):
foo = kw.pop('force', None)
x = f(*p, **kw)
if (foo):
# blah, blah
else
# blah blah
return wrapper

Now the definitions of the original functions do not include the
foo=None argument, but "actual" functions (i.e. the ones generated
by the decorator) all accept the optional foo parameter. The only
remaining problem is how to document this... I don't see how pydoc
could possibly figure this one out. I guess this is sufficient
argument to abandon this idea. Bummer.

kynn
 
S

Steven D'Aprano

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!)
 
K

kj

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


Thanks for this. It's very useful. A lot of stuff for me to chew
on.

kynn
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,151
Latest member
JaclynMarl
Top