Q: We have *args and **kwargs. Woud ***allargs be useful?

Jon Clements joncle at googlemail.com
Thu Apr 1 11:38:40 EDT 2010


On 1 Apr, 10:57, Jonathan Fine <J.F... at open.ac.uk> wrote:
> The idioms
>      def f(*args, **kwargs):
>          # Do something.
> and
>      args = (1, 2, 3)
>      kwargs = dict(a=4, b=5)
>      g(*args, **kwargs)
> are often useful in Python.
>
> I'm finding myself picking up /all/ the arguments and storing them for
> later use (as part of a testing framework).  So for me it would be nice
> if I could write
>      def f(***allargs):
>           args, kwargs = allargs
>           # Continue as before.
>
> However, if we do this then 'args' in '*args' is misleading.  So I'll
> use 'sargs' (for sequence arguments) instead.
>
> I can now write, for a suitable class Args
>      args = Args(1, 2, 3, a=4, b=5)
>      g(***args)   # Same as before.
>      sargs, kwargs = args
>      g(*sargs, **kwargs)  # Same as before.
>
> Even better, now that Args is a class we can give it a method 'call' so that
>      args.call(g)
> is equivalent to
>      g(***args)
> which removes the need for the *** construct.
>
> This reminds me of functools.partial except, of course, we've fixed all
> the arguments and left the passing of the function for later, whereas in
> partial we fix the function and some of the arguments.
>      http://docs.python.org/library/functools.html#functools.partial
>
> My view are that
> 1.  Conceptually ***allargs is useful, but an Args class would be more
> useful (not that it need be either-or).
>
> 2.  If Args were built in , there could be performance benefits.
>
> 3.  It's clearer to write
>          def(*seqargs, **kwargs):
> than
>          def(*args, **kwargs):
>
> 4.  When the Args class is used a lot, one might welcome
>          def(***args):
>              # Do something with args.
> as a shortcut (and minor speedup) for
>          def(*seqargs, **kwargs):
>              args = Args(*seqargs, **kwargs)
>              # Do something with args.
>
> I look forward to your comments on this.
>
> --
> Jonathan

I'm not sure this'll catch on, it'll be interesting to see other
comments.
However, I believe you can get the behaviour you desire something
like:

import inspect

class AllArgs(object):
    def __init__(self, func):
        self._func = func
        self._spec = inspect.getargspec(func)
        self._nposargs = len(self._spec.args)
    def __call__(self, *args, **kwdargs):
        self._func.func_globals['Args'] = (args[self._nposargs:],
kwdargs)
        return self._func(*args[:self._nposargs])

@AllArgs
def test():
    print Args

@AllArgs
def test2(a, b):
    print a, b, Args

test(1, 2, 3, 4, 5, a=3, b=5)
test2(1, 2, 3, 4, 5, c=7)

Done quickly, probably buggy, but does provide 'Args', but without
further work
swallows any *'s and **'s and might ignore defaults (hideously
untested)



hth

Jon.



More information about the Python-list mailing list