Checking for invalid keyword arguments?

R

Roy Smith

I've got a function that takes a couple of optional keyword arguments.
I want to check to make sure I didn't get passed an argument I didn't
expect. Right now I'm doing:

conversion = None
drop = False
for key, value in kwArgs.items():
if key == 'conversion':
conversion = value
elif key == 'drop':
drop = value
else:
raise TypeError ('Unexpected keyword argument %s' % key)

which seems kind of verbose. Is there a neater way to do this check?
 
A

Alex Martelli

Roy said:
I've got a function that takes a couple of optional keyword arguments.
I want to check to make sure I didn't get passed an argument I didn't
expect. Right now I'm doing:

conversion = None
drop = False
for key, value in kwArgs.items():
if key == 'conversion':
conversion = value
elif key == 'drop':
drop = value
else:
raise TypeError ('Unexpected keyword argument %s' % key)

which seems kind of verbose. Is there a neater way to do this check?

Sure, particularly in Python 2.3:

conversion = kwArgs.pop('conversion', None)
drop = kwArgs.pop('drop', False)
if kwArgs:
raise TypeError("Unexpected keyword args: %s" % kwArgs.keys())

The .pop method of dictionary objects, new in 2.3, removes a key from
a dict (if present), returning the corresponding value (or a supplied
default -- if key is absent and no default supplied, it raises). So,
if anything is still left in kwArgs after the two pops, we know there
were "unknown and ignored" keyword arguments in dict kwArgs.

Of course, in most cases you'd simply declare your function with:

<funcname>(<whatever other args>, conversion=None, drop=False):

and no **kwArgs, and just let Python do the checking for you. But
when the kwArgs DO have to come in a dict (as, rarely, does happen,
for a variety of peculiar reasons), the new 2.3 idiom will help.


Alex
 
P

Peter Hansen

Roy said:
I've got a function that takes a couple of optional keyword arguments.
I want to check to make sure I didn't get passed an argument I didn't
expect. Right now I'm doing:

conversion = None
drop = False
for key, value in kwArgs.items():
if key == 'conversion':
conversion = value
elif key == 'drop':
drop = value
else:
raise TypeError ('Unexpected keyword argument %s' % key)

which seems kind of verbose. Is there a neater way to do this check?

I'd suggest writing a general-purpose subroutine which can do the necessary
checks for you, then use a one-liner to call it with the "pattern" you
require. It might look like this for the call:

conversion, drop = checkOptArgs(kwArgs, conversion=None, drop=False)

This clearly shows the allowed keyword args, their default values, and assigns
values to the local names on return. It can of course raise the TypeError
for you if a bad name is in kwArgs.

-Peter
 
O

Oren Tirosh

I've got a function that takes a couple of optional keyword arguments.
I want to check to make sure I didn't get passed an argument I didn't
expect. Right now I'm doing:

conversion = None
drop = False
for key, value in kwArgs.items():
if key == 'conversion':
conversion = value
elif key == 'drop':
drop = value
else:
raise TypeError ('Unexpected keyword argument %s' % key)

which seems kind of verbose. Is there a neater way to do this check?

Python's built-in default argument mechanism does exactly that:

def f(conversion=None, drop=False, ...):
...

I assume that you have some good reason for using kwargs instead such as
passing a bunch of arguments together as a dict but you can unpack this
bunch by calling another function:

def f(**kwargs):
def f2(conversion=None, drop=False):
...

return f2(**kwargs)

Oren
 
P

Peter Hansen

Roy said:
I've got a function that takes a couple of optional keyword arguments.
I want to check to make sure I didn't get passed an argument I didn't
expect.

By the way, you didn't explain why you don't want to get passed arguments
you didn't expect. Can't you simply ignore them? That way you can
easily expand the API in future versions yet maintain a certain amount
of compatibility.

-Peter
 
R

Roy Smith

Peter Hansen said:
By the way, you didn't explain why you don't want to get passed arguments
you didn't expect. Can't you simply ignore them?

I'm taking some early prototype code and changing the API around a bit
as the design evolved. I thought I had changed everything, but had a
bug due to having missed a change in one place. I was calling a routine
using the old API and the now incorrect argument was just being silently
ignored.

Upon further consideration (i.e. having several people point out the
obvious to me!), I've come to realize that I don't really need the
kwArgs mechanism at all. The simplier default mechanism does exactly
what I want! Not clear what got me thinking I needed something more
complicated in the first place.

Thanks for the help.
 
P

Peter Abel

Roy Smith said:
I've got a function that takes a couple of optional keyword arguments.
I want to check to make sure I didn't get passed an argument I didn't
expect. Right now I'm doing:

conversion = None
drop = False
for key, value in kwArgs.items():
if key == 'conversion':
conversion = value
elif key == 'drop':
drop = value
else:
raise TypeError ('Unexpected keyword argument %s' % key)

which seems kind of verbose. Is there a neater way to do this check?

One solution - which reminds me of *slots* -
could be the following:
.... allowed='conversion drop some_thing else'.split()
.... not_used =filter(lambda var:var not in kwa,allowed)
.... not_allowed=filter(lambda var:var not in allowed,kwa)
.... print 'not_allowed:\t'+'\n\t\t'.join(not_allowed)
.... print 'not_used :\t'+'\n\t\t'.join(not_used)
.... not_allowed: false
foo
not_used : some_thing
else
Regards
Peter
 

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

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,053
Latest member
BrodieSola

Latest Threads

Top