Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

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

1 view
Skip to first unread message

Jonathan Fine

unread,
Apr 1, 2010, 5:57:01 AM4/1/10
to
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

Jon Clements

unread,
Apr 1, 2010, 11:38:40 AM4/1/10
to

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.

Jonathan Fine

unread,
Apr 1, 2010, 12:44:02 PM4/1/10
to
Jon Clements wrote:

Thank you for your interest, Jon.

According to http://docs.python.org/library/inspect.html we have that
func_globals is the global namespace in which this function was defined.

Hence we have
>>> def f(): pass
...
>>> f.func_globals is globals()
True
>>> f.func_globals ['x'] = 3
>>> x
3
>>>

I don't yet understand what your code is intended to do, but I'm fairly
sure you're not wishing to 'monkey-patch' a global namespace of a module.

--
Jonathan

0 new messages