Requiring arguments to be passed as keyword arguments

Michael Haggerty mhagger at blizzard.harvard.edu
Tue Oct 5 01:52:02 EDT 1999


Hi,

Sometimes I would like to write functions with arguments that are
REQUIRED to be passed as keyword arguments rather than positional
arguments.  For example, for the following function I might want the
second parameter to be passed as a keyword parameter:

    f(1, 2) # Exception
    f(1, variation=2) # OK

It is possible, though cumbersome, to enforce this requirement with
python by the use of **arguments:

    def f(x, **keyw):
        variation = keyw['variation'] # might throw confusing exception
	# test that no unwanted keyword arguments were passed:
	del keyw['variation']
	assert not keyw
        # ...

The more keyword arguments, the nastier (and these cases usually occur
when there are a large number of multiple keyword arguments).  It is
even less convenient if you want to supply default arguments.  I hope
you will all agree that it is unpleasant to have to resort to
*arguments or **arguments.

Why do I want to require keyword arguments?  Because I don't want the
order of the arguments to be part of the advertised interface to my
function.  The arguments may have no sensible ordering (for example, a
group of boolean options for which the defaults are usually used) and
thus their use as positional arguments would always be confusing.  Or
I might want to allow an indeterminate number of positional arguments,
followed by keyword arguments.

[Actually this idea arose from a real situation.  I wrote a function
with a bunch of arguments, which I intended to be passed as keyword
arguments.  A colleague called it with a bunch of positional
arguments.  Later I inserted more arguments, changing their order and
not thinking anything of it.  But suddenly my colleagues' code failed
in a non-obvious way.]

Could there be a more convenient way to enforce the keyword-argument
requirement?  Perhaps the rule that no named arguments may follow a
*argument (an asterisk argument, i.e., returning a list of all unused
positional arguments) could be replaced with the proviso that any
named arguments following a *argument MUST be passed as keyword
arguments.  Moreover, a `*' with no dummy variable name could be put
in a function signature to indicate that no more positional arguments
are allowed AND that all following arguments must be keyword
arguments:

    def f(x, *, variation):
        # same effect as above

Then keyword arguments could also easily be combined with
indeterminate numbers of positional arguments:

    def g(*x, color='red'):
        print x
        print color

    >>> g(1,2,3)
    (1, 2, 3)
    red
    >>> g(4,5,6, color='blue')
    (4, 5, 6)
    blue

(Without this change g() would have to be written with a **keyw
argument.)  This change would not break any existing code because it
is currently not allowed to include named arguments following an
*argument.

Maybe this is overkill for a feature of limited utility.  But I think
the occasional need to muck about with *arg and **keyw arguments is
one of the few tedious tasks in Python.  Similar to the new extended
calling syntax, this change would make that need rarer.

Reactions?

Michael

-- 
Michael Haggerty
mhagger at blizzard.harvard.edu




More information about the Python-list mailing list