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.
> 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!
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
def spam(*args):
x, y, z = args
# etc.
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
>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
>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.
> 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!
then add the line below:
x,y,z = *args
--
Grant
> 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
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
>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
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."
No need for a decorator though.
--
Florian Ludwig <di...@phidev.org>
Isn't this what Psyco (http://psyco.sourceforge.net/) does?
-irmen