[Python-3000] PEP3102 Keyword-Only Arguments

Steven Bethard steven.bethard at gmail.com
Mon Aug 14 22:34:54 CEST 2006


On 8/14/06, Guido van Rossum <guido at python.org> wrote:
> On 8/14/06, Steven Bethard <steven.bethard at gmail.com> wrote:
> > On 8/14/06, Guido van Rossum <guido at python.org> wrote:
> > > I believe the PEP doesn't address the opposite use case: positional
> > > arguments that should *not* be specified as keyword arguments. For
> > > example, I might want to write
> > >
> > >   def foo(a, b): ...
> > >
> > > but I don't want callers to be able to call it as foo(b=1, a=2) or
> > > even foo(a=2, b=1).
> >
> > Another use case is when you want to accept the arguments of another
> > callable, but you have your own positional arguments::
> >
> >     >>> class Wrapper(object):
> >     ...     def __init__(self, func):
> >     ...         self.func = func
> >     ...     def __call__(self, *args, **kwargs):
> >     ...         print 'calling wrapped function'
> >     ...         return self.func(*args, **kwargs)
> >     ...
> >     >>> @Wrapper
> >     ... def func(self, other):
> >     ...     return self, other
> >     ...
> >     >>> func(other=1, self=2)
> >     Traceback (most recent call last):
> >       File "<interactive input>", line 1, in ?
> >     TypeError: __call__() got multiple values for keyword argument 'self'
> >
> > It would be really nice in the example above to mark ``self`` in
> > ``__call__`` as a positional only argument.
>
> But this is a rather unusual use case isn't it? It's due to the bound
> methods machinery. Do you have other use cases?

Well, for example, unitest.TestCase.failUnlessRaises works this way.
Here's the method signature::

    def failUnlessRaises(self, excClass, callableObj, *args, **kwargs):

Which means that if you write::

    self.failUnlessRaises(TypeError, my_func, callableObj=foo)

you'll get an error since there's a name clash between the callableObj
taken by failUnlessRaises and the one taken by the my_func object.

OTOH, I haven't run into this error because I don't use camelCase
names.  Perhaps the right answer is to always use camelCase on any
arguments that you don't want to worry about conflicts, and then any
PEP 8 compliant code will never have problems. ;-)

> > > Perhaps we can use ** without following identifier to signal this?
> > > It's not entirely analogous to * without following identifier, but at
> > > least somewhat similar.
> >
> > I'm certainly not opposed to going this way, but I don't think it
> > would solve the problem above since you still need to take keyword
> > arguments.
>
> Can you elaborate?

Well, taking the failUnlessRaises signature above, if you wanted to
specify that ``self``, ``excClass`` and ``callableObj`` were
positional only arguments, I believe you'd have to write::

    def failUnlessRaises(self, excClass, callableObj, *args, **):

I believe that means that you can't use failUnlessRaises to call a
method that expects keyword arguments, e.g.::

    self.assertRaises(OptionError, parser.add_option, type='foo')


STeVe
-- 
I'm not *in*-sane. Indeed, I am so far *out* of sane that you appear a
tiny blip on the distant coast of sanity.
        --- Bucky Katt, Get Fuzzy


More information about the Python-3000 mailing list