2

I need to pass the output of a function in Python as an argument to another function. The only catch is that the 1st function returns a tuple and the entire tuple needs to be passed to the second function.

For ex:

I have a library function:

def some_function(some_string, some_number):
    # does something
    return (text,id)

Now I want to pass text and id returned from the some_function as arguments to another function. The catch is that the function has other arguments as well. I also need need to retrieve many texts and ids that will be generated by different values of some_string and number.

Depending on the condition met, I want to call another function which will look something like this

 if abcd:
     other_function(name,phone,**some_function("abcd","123")**,age)
 elif xyz:
     other_function(name,phone,**some_function("xyz","911")**,age)
 else:
     other_function(name,phone,**some_function("aaaa","000")**,age)

So what should I replace some_function("abcd","123") with so that it expands the tuple and sends both the text and id as arguments?

The other_function is defined like this

def other_function(name, phone, text, id, age):
   ...
    return 

Will simply passing some_function("aaaa","000") as an argument work?


I am asking this because I wrote a simple code to test my hypothesis and it was giving me a blank output.

def f(id,string):
    return ("123", "hello")

def a(name, age, id, words, phone):
     print name + age + id + words + phone


def main():
    a("piyush", "23", f("12", "abc"), "123")
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Piyush
  • 606
  • 4
  • 16
  • 38
  • 1
    That wouldn't give a blank output, it would raise a TypeError. – Daniel Roseman Apr 13 '15 at 10:23
  • 1
    @DanielRoseman per [the OP's link below](http://stackoverflow.com/questions/29602791/pass-function-outputs-as-arguments-to-another-function/29602952#comment47351934_29602983), it would appear that they aren't actually running anything! You're right, through; `a() takes exactly 5 arguments (4 given)`. – jonrsharpe Apr 13 '15 at 10:29

3 Answers3

4

You have two options*; either explicitly unpack the function result first:

id, words = f('12', 'abc')
a('piyush', '23', id, words, '123')

or use tuple unpacking within the call to a, and supply the last parameter by keyword:

a('piyush', '23', *f('12', 'abc'), phone='123')

If this syntax is unfamiliar, see What does ** (double star) and * (star) do for parameters?


Note that if you try to pass phone as a positional argument (rather than a keyword argument as above) after the unpacked results from f, i.e.

a('piyush', '23', *f('12', 'abc'), '123')

you will get SyntaxError: only named arguments may follow *expression. You can't have positional arguments after * unpacking, you must use the keywords for any additional arguments.


* Unless you either:

Community
  • 1
  • 1
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • In the 2nd method you mentioned, what if I call function a with variables instead of explicitly specifying the values? Will it work in a case like a(student_name,student_age,*f('12','abc'),student_age) – Piyush Apr 13 '15 at 10:21
  • @Piyush no, I have updated my answer with that information; you can't have positional arguments after `*` unpacking, you **must** use the keyword for that final argument. – jonrsharpe Apr 13 '15 at 10:27
  • 1
    @Piyush however, `a(student_name, student_age, *f('12', 'abc'), age=student_age)` would work perfectly; it's not using variables that's the issue, just that you can't have additional positional arguments after `*`. – jonrsharpe Apr 13 '15 at 10:36
2

You could also change the order of arguments in the signature:

def a(name, age, id, words, phone):
     name = name
     age=age
     id=id
     words=words
     phone=phone
     print name+age+id+words+phone

a("piyush", "23", 123, *f("12","123"))
piyush23123123hello

This way you can unpack the returned values directly when calling the function. Note, however, that this makes readability very poor and debugging harder.

Also if you don't want to use unpacking and change the you call your function you can change the code like this:

def a(name, age, id_words, phone):
     name = name
     age=age
     id=id_words[0]
     words=id_words[1]
     phone=phone
     print name+age+id+words+phone

a("piyush", "23", f("12","123"), "123")
piyush23123hello123

This has the advatage of keeping all the functions call the same as they were. Only the interal works of the function change, not the signature.

oz123
  • 27,559
  • 27
  • 125
  • 187
  • I tried running it on [ideone](http://ideone.com/bImAu2). I am still getting a blank output. – Piyush Apr 13 '15 at 10:28
  • You **can** unpack the results directly with the original call signature, *as long as you use keyword arguments for everything after the tuple unpack*. I agree that it's not ideal for debugging, compared to explicitly naming the returned values prior to the call to `a`. – jonrsharpe Apr 13 '15 at 10:35
  • 1
    @jonrsharpe: You **can** unpack the results directly with the original call signature *even without using keyword arguments for everything after the tuple unpack* as long as you can require Python 3.5. Sadly, you probably can't require Python 3.5 when it won't even be completed until 5 months from now. :) – abarnert Apr 13 '15 at 10:50
  • @jonrsharpe For sake of understanding.If I had two such functions f and g both of which returned tuples, then how would it work? Will this function run or will I have to supply parameters by keywords. Ex : a("piyush", *g("abc","zzz"), *f("12","123")) – Piyush Apr 13 '15 at 11:48
  • @Piyush why not try it and find out? – jonrsharpe Apr 13 '15 at 12:11
2

Assuming you live in the future, the right way to do this is to just unpack the tuple into the middle of the argument list, like this:

a('piyush', '23', *f('12', 'abc'), '123')

Unfortunately, you, the OP, probably don't live in the future, so this is largely only helpful for people who find this answer after September 2015 (or are willing to require a pre-release version of Python before that). This functionality was added as PEP 448, which doesn't go in until Python 3.5 (and, as of 13 April 2015, doesn't even have a patch in trunk yet—but if you really want to live dangerously, you can download the latest patch at #2292, apply it to a local fork of the repo, and build it yourself…).

So, for the time being, you have to fake it, e.g., as in jonrsharpe's answer.

Community
  • 1
  • 1
abarnert
  • 354,177
  • 51
  • 601
  • 671