forwarding *arg parameter

D

Diez B. Roggisch

Tuomas said:
... return arg
...

g(*g('foo', 'bar'))


* and ** are the symetric - they capture ellipsis arguments, and they
make iterables/dicts passed as positional/named arguments.

Diez
 
T

Tuomas

Diez said:
g(*g('foo', 'bar'))


* and ** are the symetric - they capture ellipsis arguments, and they
make iterables/dicts passed as positional/named arguments.

Diez

Thanks Diez

And what about this case if I want the result ('foo', 'bar')
.... return g(arg)
....(('foo', 'bar'),)
.... return arg[0]
....('foo', 'bar')

Where can g know it should use arg[0] when arg is forwarded?

TV
 
S

Stargaming

Tuomas said:
... return arg
...

TV Use the following then:
('foo', 'bar')

Otherwise, you would have to check if arg is a 1-tuple consisting of a
tuple and "strip" it out then.

e.g..... return arg[0] if isinstance(arg[0], tuple) else arg
....('foo', 'bar')
 
S

Steven D'Aprano

... return arg
...

The function g:
- takes the arguments 'foo' and 'bar'
- collects them in a tuple named 'arg' = ('foo', 'bar')
- returns the tuple named arg

(('foo', 'bar'),)

The function g:
- takes the argument ('foo', 'bar')
- collects it in a tuple named 'arg' = (('foo', 'bar'),)
- returns the tuple named arg

The function is doing exactly the same as in the first case, except the
arguments are different.


Why do you want to? The way the function is now makes perfect sense. All
argument types are treated in exactly the same way:

g(string) => tuple containing string
g(float) => tuple containing float
g(int) => tuple containing int
g(list) => tuple containing list
g(instance) => tuple containing instance
g(tuple) => tuple containing tuple

You could write something like this:

def g(*arg):
# Detect the special case of a single tuple argument
if len(arg) == 1 and type(arg[0]) == tuple:
return arg[0]
else:
return arg

but now tuple arguments are treated differently to all other data. Why do
you think you need that?
 
T

Tuomas

Steven D'Aprano wrote:
You could write something like this:

def g(*arg):
# Detect the special case of a single tuple argument
if len(arg) == 1 and type(arg[0]) == tuple:
return arg[0]
else:
return arg

but now tuple arguments are treated differently to all other data. Why do
you think you need that?

I am looking a shorter way to do the above in the case:

def g(*arg):
return arg

def f(*arg):
return g(arg)

How can g know if it is called directly with (('foo', 'bar'),) or via f
with ('foo', 'bar'). I coud write in f: return g(arg[0], arg[1]) if I
know the number of arguments, but what if I don't know that in design time?

TV
 
T

Tuomas

Tuomas said:
def g(*arg):
return arg

def f(*arg):
return g(arg)

How can g know if it is called directly with (('foo', 'bar'),) or via f
with ('foo', 'bar'). I coud write in f: return g(arg[0], arg[1]) if I
know the number of arguments, but what if I don't know that in design time?

So it seems that I would like to have an unpack operator:

def f(*arg):
return(!*arg)

TV
 
S

Stargaming

Tuomas said:
Tuomas said:
def g(*arg):
return arg

def f(*arg):
return g(arg)

How can g know if it is called directly with (('foo', 'bar'),) or via
f with ('foo', 'bar'). I coud write in f: return g(arg[0], arg[1]) if
I know the number of arguments, but what if I don't know that in
design time?


So it seems that I would like to have an unpack operator:

def f(*arg):
return(!*arg)

TV

Either you take one of the snippets here:
http://aspn.activestate.com/ASPN/search?query=flatten&section=PYTHONCKBK&type=Subsection
or just use arg[0] clever (as mentioned a few times in this thread).
 
T

Tuomas

Stargaming said:
Either you take one of the snippets here:
http://aspn.activestate.com/ASPN/search?query=flatten&section=PYTHONCKBK&type=Subsection

or just use arg[0] clever (as mentioned a few times in this thread).

Thanks. My solution became:
.... result = []
.... for item in arg:
.... if isinstance(item, (list, tuple)):
.... result.extend(flattern(item))
.... else:
.... result.append(item)
.... return tuple(result)
........ arg = flattern(arg)
.... return arg
........ return g(arg)
....('foo', 'bar')

TV
 
D

Dennis Lee Bieber

I am looking a shorter way to do the above in the case:

def g(*arg):
return arg

def f(*arg):
return g(arg)

How can g know if it is called directly with (('foo', 'bar'),) or via f

Typically, the responsibility should be on the CALLER, not the
CALLED..
.... return arg
.... .... return g(*arg) #<<<<<<<< unpack tuple on call
....
Note how f() is calling g() using an * -- Since f() "knows" that its
arguments were "packed" it calls g() with an unpack marker. Then g()
gets the arguments via whatever scheme it was coded to use.
.... return g(arg) #<<<<<<<<<< no tuple unpack
....
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
T

Tuomas

Dennis said:
Typically, the responsibility should be on the CALLER, not the
CALLED..



... return arg
...


... return g(*arg) #<<<<<<<< unpack tuple on call
...


('a', 1, 2)


Note how f() is calling g() using an * -- Since f() "knows" that its
arguments were "packed" it calls g() with an unpack marker. Then g()
gets the arguments via whatever scheme it was coded to use.



... return g(arg) #<<<<<<<<<< no tuple unpack
...


(('a', 1, 2),)
I fylly agree with tis: "Typically, the responsibility should be on the
CALLER, not the CALLED..". I just don't know how to unpack *arg for
calling g. I can get the len(arg), but how to formulate an unpacked call
g(arg[0], arg[1], ..). Building a string for eval("g(arg[0], arg[1],
...)") seems glumsy to me.

TV
 
D

Dennis Lee Bieber

I fylly agree with tis: "Typically, the responsibility should be on the
CALLER, not the CALLED..". I just don't know how to unpack *arg for
calling g. I can get the len(arg), but how to formulate an unpacked call
g(arg[0], arg[1], ..). Building a string for eval("g(arg[0], arg[1],
..)") seems glumsy to me.
Did you miss the example I gave? Using "*args" on the "def"
essentially says "pack remaining arguments into one tuple". Using
"*args" on a CALL says "UNPACK tuple into positional arguments"

def f(*args): <<<< pack arguments into tuple

x = g(*args) >>>> unpack args tuple when calling
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 
S

Steven D'Aprano

Thanks. My solution became:
... result = []
... for item in arg:
... if isinstance(item, (list, tuple)):
... result.extend(flattern(item))
... else:
... result.append(item)
... return tuple(result)
...... arg = flattern(arg)
... return arg
...... return g(arg)
...('foo', 'bar')


That's the most complicated do-nothing function I've ever seen. Here is a
shorter version:

def shortf(*args):
return args

('foo', 'bar')
(1, 2, 3, 4)
({}, None, 1, -1.2, 'hello world')

Actually, they aren't *quite* identical: your function rips lists apart,
which is probably not a good idea.
f("foo", [1,2,3], None) # three arguments turns into five ('foo', 1, 2, 3, None)
shortf("foo", [1,2,3], None) # three arguments stays three
('foo', [1, 2, 3], None)



I still don't understand why you are doing this. Can we have an example of
why you think you need to do this?
 
T

Tuomas

Dennis said:
I fylly agree with tis: "Typically, the responsibility should be on the
CALLER, not the CALLED..". I just don't know how to unpack *arg for
calling g. I can get the len(arg), but how to formulate an unpacked call
g(arg[0], arg[1], ..). Building a string for eval("g(arg[0], arg[1],
..)") seems glumsy to me.

Did you miss the example I gave? Using "*args" on the "def"
essentially says "pack remaining arguments into one tuple". Using
"*args" on a CALL says "UNPACK tuple into positional arguments"

def f(*args): <<<< pack arguments into tuple

Thats it:
x = g(*args) >>>> unpack args tuple when calling

Yesterday I tested something like this and got a syntax error. So I got
misunderstanding that "g(*args)" is'nt a proper syntax. Obviously my
test sentence had some other syntax error. Sorry.

TV
 
T

Tuomas

Steven said:
Thanks. My solution became:
def flattern(arg):
... result = []
... for item in arg:
... if isinstance(item, (list, tuple)):
... result.extend(flattern(item))
... else:
... result.append(item)
... return tuple(result)
...
def g(*arg):
... arg = flattern(arg)
... return arg
...
def f(*arg):
... return g(arg)
...
f('foo', 'bar')
('foo', 'bar')



That's the most complicated do-nothing function I've ever seen. Here is a
shorter version:

def shortf(*args):
return args



('foo', 'bar')

('foo', 'bar')


(1, 2, 3, 4)

(1, 2, 3, 4)


({}, None, 1, -1.2, 'hello world')

({}, None, 1, -1.2, 'hello world')

Actually, they aren't *quite* identical: your function rips lists apart,
which is probably not a good idea.

f("foo", [1,2,3], None) # three arguments turns into five

('foo', 1, 2, 3, None)
shortf("foo", [1,2,3], None) # three arguments stays three

('foo', [1, 2, 3], None)



I still don't understand why you are doing this. Can we have an example of
why you think you need to do this?

If i redefine the function g the difference comes visible:
.... if with_flattern: arg=flattern(arg)
.... return arg

If you read the whole chain you find out what we were talking of.

TV
 
S

Steve Holden

Tuomas said:
Steven said:
Thanks. My solution became:


def flattern(arg):

... result = []
... for item in arg:
... if isinstance(item, (list, tuple)):
... result.extend(flattern(item))
... else:
... result.append(item)
... return tuple(result)
...

def g(*arg):

... arg = flattern(arg)
... return arg
...

def f(*arg):

... return g(arg)
...

f('foo', 'bar')

('foo', 'bar')



That's the most complicated do-nothing function I've ever seen. Here is a
shorter version:

def shortf(*args):
return args



f('foo', 'bar')

('foo', 'bar')

shortf('foo', 'bar')

('foo', 'bar')


f(1,2,3,4)

(1, 2, 3, 4)

shortf(1,2,3,4)

(1, 2, 3, 4)


f({}, None, 1, -1.2, "hello world")

({}, None, 1, -1.2, 'hello world')

shortf({}, None, 1, -1.2, "hello world")

({}, None, 1, -1.2, 'hello world')

Actually, they aren't *quite* identical: your function rips lists apart,
which is probably not a good idea.


f("foo", [1,2,3], None) # three arguments turns into five

('foo', 1, 2, 3, None)

shortf("foo", [1,2,3], None) # three arguments stays three

('foo', [1, 2, 3], None)



I still don't understand why you are doing this. Can we have an example of
why you think you need to do this?


If i redefine the function g the difference comes visible:
.... if with_flattern: arg=flattern(arg)
.... return arg

If you read the whole chain you find out what we were talking of.

TV

Suppose you did actually want to do this you have chosen about the worst
possible way: the use of global variables to condition function
execution is a sure way to get into trouble. Consider if somebody else
want to use your function: they also have to set a global in their
program to avoid your function raising an exception.

Fortunately Python has just the thing to make such horrors unnecessary:
the default argument value. Try something like this (untested):

def g(flattening=True, *arg):
if flattening:
arg = flatten(arg)
return arg

Obviously you could use either True or False for the default value. In
the case above the function flattens by default. You could also, if you
wished, have f() take the flattening argument, and always pass it to g().

Nothing very sophisticated here, just something to help you flex your
growing Python and programming muscles.

regards
Steve
 
T

Tuomas

Steve said:
Suppose you did actually want to do this you have chosen about the worst
possible way: the use of global variables to condition function
execution is a sure way to get into trouble. Consider if somebody else
want to use your function: they also have to set a global in their
program to avoid your function raising an exception.

Do you think all discussion examples are included a producton application.
Fortunately Python has just the thing to make such horrors unnecessary:
the default argument value. Try something like this (untested):

def g(flattening=True, *arg):
if flattening:
arg = flatten(arg)
return arg

Obviously you could use either True or False for the default value. In
the case above the function flattens by default. You could also, if you
wished, have f() take the flattening argument, and always pass it to g().

Nothing very sophisticated here, just something to help you flex your
growing Python and programming muscles.

Thanks for your good purposes.

TV
 
S

Steven D'Aprano

If you read the whole chain you find out what we were talking of.

I had already read the whole thread, and I've read it again in case I
missed something the first time, and I still have no idea why you think
you need to do this. You explain *what* you want to do, but not *why* you
want to do it.
 
T

Tuomas

Steven said:
I had already read the whole thread, and I've read it again in case I
missed something the first time, and I still have no idea why you think
you need to do this. You explain *what* you want to do, but not *why* you
want to do it.

Redirecting a funtion parameter to an other function is a quite common
situation in programming. Here the question was forwarding *args
parameter. Have you ever tried this and found the difference in cases:

def f(*args):
x = g(args) # how g sees arguments in this case
x = g(*args) # and how it sees them in this case

I am happy with what Dennis Lee Bieber wrote in the second latest node
in this chain. So luckily my "flattern" is not needed because the
problem I had can be solved in the calling function.

TV
 

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
474,431
Messages
2,571,679
Members
48,796
Latest member
Greg L.

Latest Threads

Top