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

How to access args as a list?

3 views
Skip to first unread message

kj

unread,
Apr 3, 2010, 6:58:43 PM4/3/10
to


Suppose I have a function with the following signature:

def spam(x, y, z):
# etc.

Is there a way to refer, within the function, to all its arguments
as a single list? (I.e. I'm looking for Python's equivalent of
Perl's @_ variable.)

I'm aware of locals(), but I want to preserve the order in which
the arguments appear in the signature.

My immediate aim is to set up a simple class that will allow me to
iterate over the arguments passed to the constructor (plus let me
refer to these individual arguments by their names using an
instance.attribute syntax, as usual).

The best I have managed looks like this:

class _Spam(object):
def __init__(self, x, y, z):
self.__dict__ = OrderedDict(())
for p in inspect.getargspec(_Spam.__init__).args[1:]:
self.__dict__[p] = locals()[p]

def __iter__(self):
return iter(self.__dict__.values())


but rolling out inspect.getargspec for this sort of thing looks to
me like overkill. Is there a more basic approach?

P.S. this is just an example; the function I want to implement has
more parameters in its signature, with longer, more informative
names.

Andreas Waldenburger

unread,
Apr 3, 2010, 8:16:13 PM4/3/10
to
On Sat, 3 Apr 2010 22:58:43 +0000 (UTC) kj <no.e...@please.post> wrote:

> The best I have managed looks like this:
>
> class _Spam(object):
> def __init__(self, x, y, z):
> self.__dict__ = OrderedDict(())
> for p in inspect.getargspec(_Spam.__init__).args[1:]:
> self.__dict__[p] = locals()[p]
>
> def __iter__(self):
> return iter(self.__dict__.values())

Looks like you're trying to be lazy by doing extra hard work. Anything
wrong with this (?):

class Spam(object):


def __init__(self, x, y, z):

self.x = x
self.y = y
self.z = z
self.arguments = (x, y, z)

def __iter__(self):
return iter(self.arguments) # iter(...) kinda optional

With what little I know about your use case, that's how I would do it.

/W


--
INVALID? DE!

Tim Chase

unread,
Apr 3, 2010, 7:20:34 PM4/3/10
to pytho...@python.org
kj wrote:
>
>
> Suppose I have a function with the following signature:
>
> def spam(x, y, z):
> # etc.
>
> Is there a way to refer, within the function, to all its arguments
> as a single list? (I.e. I'm looking for Python's equivalent of
> Perl's @_ variable.)

It sounds like you want the "*" operator for arguments:

def foo(*args):
print "Args:", repr(args)
print " Type:", type(args)
for i, arg in enumerate(args):
print " Arg #%i = %s" % (i, arg)
foo(1)
foo("abc", "def", 42)
# pass a list as args
lst = [1,2,3]
foo(*lst)

There's also a keyword form using "**":

def foo(*args, **kwargs):
print "Args:", repr(args)
print " Type:", type(args)
print "Keyword Args:", repr(kwargs)
print " Type:", type(kwargs)
for i, arg in enumerate(args):
print " Arg #%i = %s" % (i+1, arg)
for i, (k, v) in enumerate(kwargs.items()):
print " kwarg #%i %r = %s" % (i+1, k, v)
foo(1, "hello", something="Whatever", baz=42)
# pass a list and a dict:
lst = [1,2,3]
dct = {100:10, 200:11}
foo(*lst, **dct)

Both prevent introspection, so if you want the auto-generated
help to populate with named arguments, you'd have to use the
inspection method you're currently using. But generally, if you
want to be able to treat the args as lists/tuples/dicts, you
don't care about the names given.

-tim


MRAB

unread,
Apr 3, 2010, 7:20:52 PM4/3/10
to pytho...@python.org
I think the closest approach to what you're asking is to capture the
arguments as a list and then bind them to local names:

def spam(*args):
x, y, z = args
# etc.

Rolando Espinoza La Fuente

unread,
Apr 3, 2010, 7:21:38 PM4/3/10
to kj, pytho...@python.org
On Sat, Apr 3, 2010 at 6:28 PM, kj <no.e...@please.post> wrote:
> Is there a way to refer, within the function, to all its arguments
> as a single list?  (I.e. I'm looking for Python's equivalent of
> Perl's @_ variable.)
>

def spam(*args, **kwargs):
print args
print kwargs

class Spam:
def __init__(self, *args, **kwargs):
print args
print kwargs

That's what are you looking for?

Regards,

~Rolando

kj

unread,
Apr 3, 2010, 7:52:42 PM4/3/10
to
In <hp8h73$k17$1...@reader1.panix.com> kj <no.e...@please.post> writes:

>Suppose I have a function with the following signature:

>def spam(x, y, z):
> # etc.

>Is there a way to refer, within the function, to all its arguments
>as a single list? (I.e. I'm looking for Python's equivalent of
>Perl's @_ variable.)

>I'm aware of locals(), but I want to preserve the order in which
>the arguments appear in the signature.

>My immediate aim is to set up a simple class that will allow me to

>iterate over the arguments passed to the constructor (plus letS me
^^^^^^^^^^^^


>refer to these individual arguments by their names using an

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>instance.attribute syntax, as usual).
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The underlined portion explains why __init__(self, *args) fails to
fit the bill.

>P.S. this is just an example; the function I want to implement has
>more parameters in its signature, with longer, more informative
>names.

Andreas, perhaps this paragraph explains why I find your solution
unappealing: it requires typing the same thing over and over,
which increases the chances of bugs. That's the reason I avoid
such repetitiveness, not laziness, as you so were so quick to accuse
me of.

~K

kj

unread,
Apr 3, 2010, 7:55:10 PM4/3/10
to
In <hp8kc9$dg7$1...@reader1.panix.com> kj <no.e...@please.post> writes:

>In <hp8h73$k17$1...@reader1.panix.com> kj <no.e...@please.post> writes:

>>Suppose I have a function with the following signature:

>>def spam(x, y, z):
>> # etc.

>>Is there a way to refer, within the function, to all its arguments
>>as a single list? (I.e. I'm looking for Python's equivalent of
>>Perl's @_ variable.)

>>I'm aware of locals(), but I want to preserve the order in which
>>the arguments appear in the signature.

>>My immediate aim is to set up a simple class that will allow me to
>>iterate over the arguments passed to the constructor (plus letS me
> ^^^^^^^^^^^^
>>refer to these individual arguments by their names using an
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>instance.attribute syntax, as usual).
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

>The underlined portion explains why __init__(self, *args) fails to
>fit the bill.

The minute I hit "send" I realized that this is wrong. Sorry.

Thanks.

Andreas Waldenburger

unread,
Apr 3, 2010, 9:42:14 PM4/3/10
to
On Sat, 3 Apr 2010 23:52:42 +0000 (UTC) kj <no.e...@please.post> wrote:

> In <hp8h73$k17$1...@reader1.panix.com> kj <no.e...@please.post> writes:
>

> [snip]


> >P.S. this is just an example; the function I want to implement has
> >more parameters in its signature, with longer, more informative
> >names.
>
> Andreas, perhaps this paragraph explains why I find your solution
> unappealing: it requires typing the same thing over and over,
> which increases the chances of bugs. That's the reason I avoid
> such repetitiveness, not laziness, as you so were so quick to accuse
> me of.
>

First up: I am sorry, I did not mean to offend. I apologize if I did.

But I stand by my point: If this class is the only instance of this
pattern, you'll only do this once. I see no reason to automate
something that will run only once anyway.

From your own reply to the above it seems that the *args-notation
solves your problem (if I understand correctly). Since I'm patronizing
by nature, I'd like to weigh in on this: The approach you describe
seems like a Perl-ism[1]. *args is meant for variable argument lists.
Using it as a shortcut for "many formal parameters" is misuse of that
feature (not the worst kind, but not very good either). In addition to
creating the impression that the function takes a variable number of
arguments, it breaks introspection/self-documentation. Also, "many
formal parameters" can be a signal to rethink the approach altogether.
I feel that if a function has more than 6 or so parameters, I'm missing
an opportunity to simplify my code.

All of the above is philosophy, of course, and mine to boot, so feel
free to ignore my rambling. But maybe you can elaborate a bit on why
you need names *and* sequence of your parameters preserved and why
there need to be so many of them. Perhaps a fresh perspective on this
will yield a less problematic approach.

Then again, maybe I have wasted your time enough already. ;)

/W

--
INVALID? DE!

Grant Edwards

unread,
Apr 3, 2010, 9:14:24 PM4/3/10
to
On 2010-04-03, kj <no.e...@please.post> wrote:
> In <hp8h73$k17$1...@reader1.panix.com> kj <no.e...@please.post> writes:
>
>>Suppose I have a function with the following signature:
>
>>def spam(x, y, z):
>> # etc.
>
>>Is there a way to refer, within the function, to all its arguments
>>as a single list? (I.e. I'm looking for Python's equivalent of
>>Perl's @_ variable.)
>
>>I'm aware of locals(), but I want to preserve the order in which
>>the arguments appear in the signature.
>
>>My immediate aim is to set up a simple class that will allow me to
>>iterate over the arguments passed to the constructor (plus letS me
> ^^^^^^^^^^^^
>>refer to these individual arguments by their names using an
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>instance.attribute syntax, as usual).
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> The underlined portion explains why __init__(self, *args) fails to
> fit the bill.

then add the line below:

x,y,z = *args

--
Grant

Steven D'Aprano

unread,
Apr 3, 2010, 11:09:43 PM4/3/10
to
On Sat, 03 Apr 2010 22:58:43 +0000, kj wrote:

> Suppose I have a function with the following signature:
>
> def spam(x, y, z):
> # etc.
>
> Is there a way to refer, within the function, to all its arguments as a
> single list? (I.e. I'm looking for Python's equivalent of Perl's @_
> variable.)

Does this help?

>>> def spam(a, b, c=3, d=4):
... pass
...
>>> spam.__code__.co_varnames
('a', 'b', 'c', 'd')

The hardest part is having the function know its own name.

I see that you are already using the inspect module. That almost
certainly is the correct approach. I'd be surprised if inspect is too
heavyweight, but if it is, you can pull out the bits you need into your
own function.


--
Steven

Francesco Bochicchio

unread,
Apr 4, 2010, 6:11:59 AM4/4/10
to

Hi, I once tried something to emulate in python the way Scala language
allows to automatically generate class attributes from constructor
parameter. I never tried in real code, but see if it fits your bill.
It uses class decorators though, so only works with python3. Here is
my code:

class FieldsDecorator:
"""It adds a generic scala-like constructor to a class.
You can create as instance as c = MyClass(f1=3, f2=4)
and have automatically c.f1=3, c.f2=4.
Only parameter names listed in the decorator are allowed.
"""
def __init__(self, *names):
self.names = names

def __call__(self, cls):
def constructor(instance, **kwds):
for n,v in kwds.items():
if n in self.names:
setattr(instance, n, v)
else: raise TypeError("%s is not a valid field" % s )
setattr(cls, '__init__', constructor )
return cls


@FieldsDecorator("uno", "due")
class Prova:
pass

p = Prova(uno=12, due=9)
print (p.uno, p.due )

Ciao
----
FB

kj

unread,
Apr 5, 2010, 2:49:08 PM4/5/10
to
In <4bb802f7$0$8827$c3e...@news.astraweb.com> Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.au> writes:

>On Sat, 03 Apr 2010 22:58:43 +0000, kj wrote:

>> Suppose I have a function with the following signature:
>>
>> def spam(x, y, z):
>> # etc.
>>
>> Is there a way to refer, within the function, to all its arguments as a
>> single list? (I.e. I'm looking for Python's equivalent of Perl's @_
>> variable.)

>Does this help?

>>>> def spam(a, b, c=3, d=4):
>... pass
>...
>>>> spam.__code__.co_varnames
>('a', 'b', 'c', 'd')

That's very handy. Thanks!

>The hardest part is having the function know its own name.

Indeed. Why Python does not provide this elmentary form of
introspection as a built-in variable is extremely puzzling to me
(even--no, *more so*--after reading PEP 3130).

>I see that you are already using the inspect module. That almost
>certainly is the correct approach. I'd be surprised if inspect is too
>heavyweight, but if it is, you can pull out the bits you need into your
>own function.

That's a good idea. Thanks!

~K

Steve Howell

unread,
Apr 6, 2010, 12:55:13 AM4/6/10
to
On Apr 5, 11:49 am, kj <no.em...@please.post> wrote:

> In <4bb802f7$0$8827$c3e8...@news.astraweb.com> Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.au> writes:
>
> >On Sat, 03 Apr 2010 22:58:43 +0000, kj wrote:
> >> Suppose I have a function with the following signature:
>
> >> def spam(x, y, z):
> >>     # etc.
>
> >> Is there a way to refer, within the function, to all its arguments as a
> >> single list?  (I.e. I'm looking for Python's equivalent of Perl's @_
> >> variable.)
> >Does this help?
> >>>> def spam(a, b, c=3, d=4):
> >...     pass
> >...
> >>>> spam.__code__.co_varnames
> >('a', 'b', 'c', 'd')
>
> That's very handy.  Thanks!
>
> >The hardest part is having the function know its own name.
>
> Indeed.  Why Python does not provide this elmentary form of
> introspection as a built-in variable is extremely puzzling to me
> (even--no, *more so*--after reading PEP 3130).
>

The Rejection Notice in the PEP certainly not give very many details
for why the PEP was rejected.

The first question in the Open Issues could easily be answered "yes."

Message has been deleted
Message has been deleted

Florian Ludwig

unread,
Apr 6, 2010, 11:27:56 AM4/6/10
to Luis M., pytho...@python.org
On Mon, 2010-04-05 at 22:45 -0700, Luis M. González wrote:
> The above post gave me an idea (very naive, of couse).
> What if I write a simple decorator to figure out the types of every
> function, and then we use it as a base for a simple method-jit
> compiler for python?
I think its what done before by psyco:
http://psyco.sourceforge.net/

No need for a decorator though.

--
Florian Ludwig <di...@phidev.org>

Irmen de Jong

unread,
Apr 6, 2010, 3:56:11 PM4/6/10
to
On 6-4-2010 8:22, Luis M. González wrote:
> The above post gave me an idea (very naive, of couse).
> What if I write a simple decorator to figure out the types of every
> function, and then we use it as a base for a simple method-jit
> compiler for python?
> example:
> def typer(f):
> def wrap(*args):
> a = f.func_code.co_varnames
> b = [type(i) for i in args]
> return dict(zip(a,b))
> return wrap
> @typer

> def spam(a, b, c=3, d=4):
> pass
>>>> spam(8,'hello',9.9, 10)
>
> {'a':<type 'int'>, 'c':<type 'float'>, 'b':<type 'str'>, 'd':
> <type
> 'int'>}
> So by using this information, we record all the argument types used
> the first time each function/method is executed, and then we generate
> optimized code for them.
> From this point on, a guard should check if all arguments remain the
> same and, if so, the optimized code is run.
> Otherwise, just fall back to the interpreter.
> He! I have no idea how to implement it...
> Any guru out there?
> Luis

Isn't this what Psyco (http://psyco.sourceforge.net/) does?

-irmen


0 new messages