How to access args as a list?

K

kj

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.
 
T

Tim Chase

kj said:
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
 
M

MRAB

kj said:
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.
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.
 
R

Rolando Espinoza La Fuente

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
 
K

kj

In said:
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
 
K

kj

In said:
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.
 
A

Andreas Waldenburger

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
 
G

Grant Edwards

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

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

then add the line below:

x,y,z = *args
 
A

Andreas Waldenburger

[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
 
S

Steven D'Aprano

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?
.... pass
....('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.
 
F

Francesco Bochicchio

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.

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
 
K

kj

Does this help?
... pass
...
('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
 
S

Steve Howell

That's very handy.  Thanks!


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."
 
L

Luis M. González

Does this help?


...     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.

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
{'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
 
F

Florian Ludwig

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top