another newbie question: why should you use "*args" ?

S

stef

why should I use *args,
as in my ignorance,
making use of a list (or tupple) works just as well,
and is more flexible in it's calling.
So the simple conclusion might be: never use "*args",
or am I overlooking something ?

# method 1
def execute (self, *args):
for i in range ( len(args) ):
... do something

# method 2
def chunk_plot(self, list):
for i in range ( len(list) ):
.... do something


# calling method 1:
execute (S[0], S[4] )

# calling method 2:
execute ( ( S[0], S[4] ) )

# or *the extra flexibility)
mylist = ( S[0], S[4] )
execute ( mylist )


thanks,
Stef Mientki
 
D

Diez B. Roggisch

stef said:
why should I use *args,
as in my ignorance,
making use of a list (or tupple) works just as well,
and is more flexible in it's calling.
So the simple conclusion might be: never use "*args",
or am I overlooking something ?

Yup. For example decorators, that wrap functions. If you do that, you want
to return a function that captures all passed arguments, does something,
and then invokes the original function with the original arguments. Like
this:


def logging_decorator(f):
def _f(*args, **kwargs):
print "calling %r with (%r, %r)", % (f, args, kwargs)
return f(*args, **kwargs)

return _f


@logging_decorator
def im_just_a_function(some, argument, and, other=None):
pass




Diez
 
B

Bruno Desthuilliers

stef a écrit :
why should I use *args,
as in my ignorance,
making use of a list (or tupple) works just as well,
and is more flexible in it's calling.

Err... How so ?
So the simple conclusion might be: never use "*args",
or am I overlooking something ?

Try writing generic higher order functions without it, and let us know.

dummy example:

def trace(func, *args, **kw):
print "calling %s with %s %s" % (func.__name__, str(args), kw)
try:
result = func(*args, **kw)
print "got %s" % str(result)
return result
except Exception, e:
print "raised : %s" % e
raise
 
D

Dustan

why should I use *args,
as in my ignorance,
making use of a list (or tupple) works just as well,
and is more flexible in it's calling.

Others have mentioned the instances in which it's actually useful -
for catch-all arguments. But you also should take into consideration
the aesthetics, since python is supposed to be an aesthetically nice
language.
So the simple conclusion might be: never use "*args",
or am I overlooking something ?

# method 1
def execute (self, *args):
for i in range ( len(args) ):
... do something

# method 2
def chunk_plot(self, list):
for i in range ( len(list) ):
.... do something

It's bad practice to use built-ins like 'list' as a regular variable
name.
# calling method 1:
execute (S[0], S[4] )

# calling method 2:
execute ( ( S[0], S[4] ) )

Let's take a look at those side-by-side:
execute (S[0], S[4] )
execute ( ( S[0], S[4] ) )

Now, which one *looks* better?
# or *the extra flexibility)
mylist = ( S[0], S[4] )
execute ( mylist )

Also, take into consideration the opposite end of the pole; you have
your list of arguments (args), and your about to call a function that
was declared something like this:
def someFunction(arg1, arg2, arg3):
# etc.
Which is clearer?
someFunction(*args)
someFunction(args[0], args[1], args[2])

And if you've got a variable number of arguments, it becomes virtually
impossible to avoid using the *args syntax.

And that doesn't even begin to cover the need for **kargs! (which, if
you haven't noticed, is generally used next to *args)

It turns out that it's not really necessary in a static-typed language
like java (although java 5.0 introduced it); it's the dynamic nature
of python that makes these syntactic sugars necessary. And without
them, function calls can get really ugly.
 
S

stef

It's bad practice to use built-ins like 'list' as a regular variable
name.
ok, but it was just an example (in practice, I always use very long
names ;-)
# calling method 1:
execute (S[0], S[4] )

# calling method 2:
execute ( ( S[0], S[4] ) )

Let's take a look at those side-by-side:
execute (S[0], S[4] )
execute ( ( S[0], S[4] ) )

Now, which one *looks* better?

# or *the extra flexibility)
mylist = ( S[0], S[4] )
execute ( mylist )

Also, take into consideration the opposite end of the pole; you have
your list of arguments (args), and your about to call a function that
was declared something like this:
def someFunction(arg1, arg2, arg3):
# etc.
Which is clearer?
someFunction(*args)
someFunction(args[0], args[1], args[2])

And if you've got a variable number of arguments, it becomes virtually
impossible to avoid using the *args syntax.
# So with this construct, I have all flavours:

def chunk_plot(*args):
if len(args)==1: my_example_var = args[0]
else: my_example_var = args
for i in range ( len ( my_example_var ) ):
... do something with my_example_var

# calling the procedure
chunk_plot (S[1], S[4])
chunk_plot ( ( S[1], S[4] ) )
my_action_list = ( S[1], S[2] )
chunk_plot ( my_action_list )


And sorry, no need for kwargs for now ;-)

thanks guys,
Stef
 
E

Eugene Antimirov

stef said:
# method 2
def chunk_plot(self, list):
for i in range ( len(list) ):
.... do something


And one note more. Just to be more pythonic you shouldn't use form
range(len(blabla)). Instead use:

for i in list:
.....blabla...
 
S

stef

Eugene said:
And one note more. Just to be more pythonic you shouldn't use form
range(len(blabla)). Instead use:

for i in list:
....blabla...
I would love that,
but please tell me how (I need an integer counter for something else too):

def chunk_plot(*args):
if len(args) == 1: list = args[0]
else: list = args

color = ['g','r','b','y','m']
plot ( list[0], color[0])
hold (True)
for i in range ( 1, len(list) ):
plot ( list, color )



cheers,
Stef
 
J

Jeffrey Froman

stef said:
I would love that,
but please tell me how (I need an integer counter for something else too):

for index, item in enumerate(args):
...


Jeffrey
 
M

Marc 'BlackJack' Rintsch

Eugene said:
And one note more. Just to be more pythonic you shouldn't use form
range(len(blabla)). Instead use:

for i in list:
....blabla...
I would love that,
but please tell me how (I need an integer counter for something else too):

def chunk_plot(*args):
if len(args) == 1: list = args[0]
else: list = args

color = ['g','r','b','y','m']
plot ( list[0], color[0])
hold (True)
for i in range ( 1, len(list) ):
plot ( list, color )


No need for the counter here.

for args in zip(list[1:], color[1:]):
plot(*args)

Ciao,
Marc 'BlackJack' Rintsch
 
S

stef

I would love that,
but please tell me how (I need an integer counter for something else too):

def chunk_plot(*args):
if len(args) == 1: list = args[0]
else: list = args

color = ['g','r','b','y','m']
plot ( list[0], color[0])
hold (True)
for i in range ( 1, len(list) ):
plot ( list, color )


No need for the counter here.

for args in zip(list[1:], color[1:]):
plot(*args)

that looks nice, thanks!
All the other people also thanks, "enumerate" looks also better than
range(len( nice !
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top