Ignore python multiple return value
Asked Answered
N

12

404

Say I have a Python function that returns multiple values in a tuple:

def func():
    return 1, 2

Is there a nice way to ignore one of the results rather than just assigning to a temporary variable? Say if I was only interested in the first value, is there a better way than this:

x, temp = func()
Nichols answered 10/1, 2009 at 22:12 Comment(2)
I got curious of this too coming from Matlab's similar notion of Ignore Function Outputs where they use ~ as the syntax to ignore a particular return variableMidvictorian
You selected the wrong answer as solutionGaiseric
D
353

One common convention is to use a "_" as a variable name for the elements of the tuple you wish to ignore. For instance:

def f():
    return 1, 2, 3

_, _, x = f()
Daleth answered 10/1, 2009 at 22:18 Comment(20)
Very interesting concept, but not very Pythonic. However, neither is my submitted solution. :-P May I ask, where did you hear of this convention? I'd like to learn how popular it is.Deka
That's the concept I've heard of before but couldn't remember. Not sure where I heard of it from though.Nichols
I've seen it in various pieces of code here and there. If you do a grep -w '_,' *.py in the standard Python library, you'll find a few instances of it. For example, UserDict.py has a couple instances of it. I've also seen it in packages like Pygments and Django.Daleth
@Evan I actually find this to be very Pythonic, especially given python's propensity for using underscores. (int.__mul__, iter, builtins, etc.)Phares
It's definitely standard in the python community, I've been doing it so long I don't remember why I started doing it. I was surprised I didn't find it in PEP 8.Quinquepartite
-1: this "convention" sucks when you add gettext functionality to someone else's code (that defines a function called '_') so it should be bannedRomanticism
Good point--though it's debatable whether gettext's insistence on installing a function called "" is a good idea. Personally, I find it a little ugly. Regardless, the use of "" as a throwaway variable is widespread.Daleth
This convention is also common in Haskell. Anyone know where it originated?Turnspit
This is neat. Seems to me that it comes from the Perl world.Discursion
The origin, as far as I can tell, is ML. This is supported by the same usage in functional languages, especially ML-derived/-inspired languages such as OCaml, F#, Nemerle, etc.Squelch
-1: _ means "last output" in IPython. I would never assign something to it.Louvain
@Draemon: ipython.scipy.org/doc/manual/html/interactive/…Louvain
Ok, I didn't notice the "I" - thanks for the reference. IMHO you can't expect others not to use a variable just because one Python app defines its own magical use for it.Lamori
some IDEs such as PyDev will give you a warning on this, because you have unused variables.Bacchic
@Draemon: There are two examples so far of the underscore having other purposes. It's not a throwaway variable and should not be treated as one. The function outputs a tuple; use it like a tuple.Louvain
@Louvain that's the point. python already assigns to _. explicitly assigning to _ is equivalent to assigning to nothing, which is the goal. (i.e., normally both _ and a new variable are assigned to -- this leaves out the new variable.)Research
@Romanticism sure, any Python convention that fails to be consistent with non-Python software should be banned. hell, while we're at it, let's just ban Python. maybe the people who wrote gettext can recommend something else.Research
Regardless of which specific module wants to use _ why should one use any name and totally discard it, when the name could be used by something else? Why not just do x, print = func() for example? func()[0] is clearly much better, truly discards the parts of the tuple not needed and doesn't pollute the namespace.Cavefish
Another disadvantage of assigning to _ (or to any variable name) is that the reference associated with that name will then persist until the end of the current function, or until you explicitly del _. But since the objected is unwanted, it will usually make more sense for it to be garbage-collected ASAP.Meteorite
All the naysayers here talking about _ already being used, not realizing you can just use two underscores __...Lemos
H
764

You can use x = func()[0] to return the first value, x = func()[1] to return the second, and so on.

If you want to get multiple values at a time, use something like x, y = func()[2:4].

Hayward answered 10/1, 2009 at 22:14 Comment(18)
This should be the accepted answer. You can also use things like func()[2:4] if you only want some of the return values.Louvain
This sucks because you have to call func() multiple times. It's a waste of CPU timeShellans
It doesn't call the function multiple times: >>> def test(): ... print "here" ... return 1,2,3 ... >>> a,b = test()[:2] here [edit: sorry that code didn't come through, aparently you only get one line in comments. For those not familiar >>> and ... are the start of a new line in the python shell]Bacchic
@TylerLong: No you don't. If you want more than one value at a time, use something like x, y = func()[0:1]Louvain
@Louvain it makes some sense but it is not a general solution. Suppose that func() returns 100 values and I want the 13th, 25th, 58th, 89th and 98th, then I still have to call func() multiple times.Shellans
@TylerLong: I think _, _, _, _, _, _, _, _, _, _, _, _, _, a, _, _, _, _, _, _, _, _, _, _, _, b, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, c, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, d, _, _, _, _, _, _, _, _, e, _ = func() is less clear than calling the function multiple times, but that's just my opinion. If your function returns that many items, I think using numpy would be preferable: a, b, c, d, e = func()[[13, 25, 58, 89, 98]]Louvain
@Louvain I think this is better and does not need numpy and does not need to call func() multiple times: result = func() a = result[13] b = result[25] ...Shellans
How do I use this syntax with an in statement such as when I would use for (_, _, x, _) in something(): ?Terrieterrier
@Zitrax: the only real way to use this syntax in the way you describe would be to introduce a variable for the values returned by something(), i.e. for spam in something(): followed by x = spam[2].Hayward
@Terrieterrier don't forget you can always save the return value and reuse it: result=something() and then result[2] and so on..Towery
@Louvain this obviously doesn't work when the goal is to suppress output during an interactive session from a function that returns a single value.Research
@dbliss I don't understandLouvain
@dbliss Ok, but that's a different question. This one is about things that return sequences. You want something like reload(numpy); to suppress IPython's output: https://mcmap.net/q/87632/-how-do-you-suppress-output-in-jupyter-running-ipython/125507Louvain
@Louvain if you are dogmatically opposed to _, then yes, you can use a combination of indexing and semicolons to handle unwanted output from functions. i am not so ideologically disposed, so i will continue to use the elegant, general-purpose solution _ = . . . i have never written a function that returns 100 values only a seemingly random subset of which i actually need.Research
@dbliss You're not even talking about the same thing. This question is about assigning only a subset of a returned object, while you're talking about suppressing IPython's printing of a returned object when it's not assigned. The semicolon is what you're looking for.Louvain
This style is not nice when you want to ignore one or a few values in between, e.g. x, __, y = func()Kokoruda
Is there any difference between both approaches, if it comes to copying data? E.G. pre-numpy 1.11 gradient may return a list of quite big arrays. Is the copying process bypassed by x,y = np.gradient(z)[1,2] for the other arrays within the output list?Hybridism
This should be an excepted answer.Quartersaw
D
353

One common convention is to use a "_" as a variable name for the elements of the tuple you wish to ignore. For instance:

def f():
    return 1, 2, 3

_, _, x = f()
Daleth answered 10/1, 2009 at 22:18 Comment(20)
Very interesting concept, but not very Pythonic. However, neither is my submitted solution. :-P May I ask, where did you hear of this convention? I'd like to learn how popular it is.Deka
That's the concept I've heard of before but couldn't remember. Not sure where I heard of it from though.Nichols
I've seen it in various pieces of code here and there. If you do a grep -w '_,' *.py in the standard Python library, you'll find a few instances of it. For example, UserDict.py has a couple instances of it. I've also seen it in packages like Pygments and Django.Daleth
@Evan I actually find this to be very Pythonic, especially given python's propensity for using underscores. (int.__mul__, iter, builtins, etc.)Phares
It's definitely standard in the python community, I've been doing it so long I don't remember why I started doing it. I was surprised I didn't find it in PEP 8.Quinquepartite
-1: this "convention" sucks when you add gettext functionality to someone else's code (that defines a function called '_') so it should be bannedRomanticism
Good point--though it's debatable whether gettext's insistence on installing a function called "" is a good idea. Personally, I find it a little ugly. Regardless, the use of "" as a throwaway variable is widespread.Daleth
This convention is also common in Haskell. Anyone know where it originated?Turnspit
This is neat. Seems to me that it comes from the Perl world.Discursion
The origin, as far as I can tell, is ML. This is supported by the same usage in functional languages, especially ML-derived/-inspired languages such as OCaml, F#, Nemerle, etc.Squelch
-1: _ means "last output" in IPython. I would never assign something to it.Louvain
@Draemon: ipython.scipy.org/doc/manual/html/interactive/…Louvain
Ok, I didn't notice the "I" - thanks for the reference. IMHO you can't expect others not to use a variable just because one Python app defines its own magical use for it.Lamori
some IDEs such as PyDev will give you a warning on this, because you have unused variables.Bacchic
@Draemon: There are two examples so far of the underscore having other purposes. It's not a throwaway variable and should not be treated as one. The function outputs a tuple; use it like a tuple.Louvain
@Louvain that's the point. python already assigns to _. explicitly assigning to _ is equivalent to assigning to nothing, which is the goal. (i.e., normally both _ and a new variable are assigned to -- this leaves out the new variable.)Research
@Romanticism sure, any Python convention that fails to be consistent with non-Python software should be banned. hell, while we're at it, let's just ban Python. maybe the people who wrote gettext can recommend something else.Research
Regardless of which specific module wants to use _ why should one use any name and totally discard it, when the name could be used by something else? Why not just do x, print = func() for example? func()[0] is clearly much better, truly discards the parts of the tuple not needed and doesn't pollute the namespace.Cavefish
Another disadvantage of assigning to _ (or to any variable name) is that the reference associated with that name will then persist until the end of the current function, or until you explicitly del _. But since the objected is unwanted, it will usually make more sense for it to be garbage-collected ASAP.Meteorite
All the naysayers here talking about _ already being used, not realizing you can just use two underscores __...Lemos
C
150

If you're using Python 3, you can you use the star before a variable (on the left side of an assignment) to have it be a list in unpacking.

# Example 1: a is 1 and b is [2, 3]

a, *b = [1, 2, 3]

# Example 2: a is 1, b is [2, 3], and c is 4

a, *b, c = [1, 2, 3, 4]

# Example 3: b is [1, 2] and c is 3

*b, c = [1, 2, 3]       

# Example 4: a is 1 and b is []

a, *b = [1]
Cauda answered 11/1, 2009 at 21:15 Comment(2)
You can also use a, *_ = f() to ignore arbitrary number of returned values after a.Antagonism
Just to add to this useful feature, this only works if your LHS assignment is made of several variables. In other words, this is a syntax error: *b = [1, 2]Glossal
K
29

The common practice is to use the dummy variable _ (single underscore), as many have indicated here before.

However, to avoid collisions with other uses of that variable name (see this response) it might be a better practice to use __ (double underscore) instead as a throwaway variable, as pointed by ncoghlan. E.g.:

x, __ = func()
Keese answered 6/3, 2015 at 10:1 Comment(1)
Not a bad idea at all. But then '_ _ ' would declare a variable in the namespace. Whereas, ' _ ' does not declare unless specifically used on the left hand side of the assignment statement like above (eg: a, _, _ = 1,8,9). Until that point, it stores the result of the last statement executed which if you want to catch, you'd normally use a variable to store that value. And this is why, ' _ ' is the suggested variable name to catch junk values. ' _ ' values get overwritten soon after another statement is executed. In case of '_ _', value would remain there until GC cleans it off.Shaikh
D
24

Remember, when you return more than one item, you're really returning a tuple. So you can do things like this:

def func():
    return 1, 2

print func()[0] # prints 1
print func()[1] # prints 2
Deka answered 10/1, 2009 at 22:20 Comment(1)
Useful for the syntax. A problem with this is that it requires calling the function multiple times. For such a trivial function, this is no big deal. But, in more complex functions, this could be undesirable. Good to know there are many approaches....Aw
E
22

The best solution probably is to name things instead of returning meaningless tuples (unless there is some logic behind the order of the returned items). You can for example use a dictionary:

def func():
    return {'lat': 1, 'lng': 2}
    
latitude = func()['lat']

You could even use namedtuple if you want to add extra information about what you are returning (it's not just a dictionary, it's a pair of coordinates):

from collections import namedtuple 

Coordinates = namedtuple('Coordinates', ['lat', 'lng'])

def func():
    return Coordinates(lat=1, lng=2)

latitude = func().lat

If the objects within your dictionary/tuple are strongly tied together then it may be a good idea to even define a class for it. That way you'll also be able to define more complex operations. A natural question that follows is: When should I be using classes in Python?

Most recent versions of python (≥ 3.7) have dataclasses which you can use to define classes with very few lines of code:

from dataclasses import dataclass

@dataclass
class Coordinates:
    lat: float = 0
    lng: float = 0

def func():
    return Coordinates(lat=1, lng=2)

latitude = func().lat

The primary advantage of dataclasses over namedtuple is that its easier to extend, but there are other differences. Note that by default, dataclasses are mutable, but you can use @dataclass(frozen=True) instead of @dataclass to force them being immutable.

Here is a video that might help you pick the right data class for your use case. And a another video on attrs vs. dataclass that enlight some interesting details about why attrs might be interesting.

Estrellaestrellita answered 22/2, 2018 at 16:34 Comment(1)
This is the only answer that gets at the heart of the problem hidden in this question. If you are trying to select one of a function's tuple outputs, they probably shouldn't be in a tuple. Tuples are for things that "go together" in an ordered way. In the OP's case, they are (probably) "qualitatively different" outputs, and should really be named in some way. Asking a reader to understand what the first and second output refer to, when there's no natural ordering, is a recipe for trouble.Dunois
K
19

Three simple choices.

Obvious

x, _ = func()

x, junk = func()

Hideous

x = func()[0]

And there are ways to do this with a decorator.

def val0( aFunc ):
    def pick0( *args, **kw ):
        return aFunc(*args,**kw)[0]
    return pick0

func0= val0(func)
Kinard answered 10/1, 2009 at 22:19 Comment(4)
I really prefer the _ variable. It's very obvious that you're ignoring a valueCarce
Your examples are backwards. x, _ = func() is hideous, and x = func()[0] is obvious. Assigning to a variable and then not using it? The function is returning a tuple; index it like a tuple.Louvain
In pattern matching languages, from which Python derived this pattern, the 'obvious' method is indeed obvious, not hideous, and canonical. Although, in such languages the wildcard is a supported language feature whereas in Python it's a real variable and gets bound, which is a little unpalatable.Blastula
For list processing languages, from which Python is derived ;), list accessors such as a[0], a[:] (list copy), a[::2] (every two elements), and a[i:] + a[:i] (rotate a list), are indeed, also obvious and canonical.Seaddon
C
6

This seems like the best choice to me:

val1, val2, ignored1, ignored2 = some_function()

It's not cryptic or ugly (like the func()[index] method), and clearly states your purpose.

Corregidor answered 11/1, 2009 at 17:44 Comment(1)
This seems slightly better: val1, val2, *ignored = some_function()Bashibazouk
S
6

This is not a direct answer to the question. Rather it answers this question: "How do I choose a specific function output from many possible options?".

If you are able to write the function (ie, it is not in a library you cannot modify), then add an input argument that indicates what you want out of the function. Make it a named argument with a default value so in the "common case" you don't even have to specify it.

    def fancy_function( arg1, arg2, return_type=1 ):
        ret_val = None
        if( 1 == return_type ):
            ret_val = arg1 + arg2
        elif( 2 == return_type ):
            ret_val = [ arg1, arg2, arg1 * arg2 ]
        else:
            ret_val = ( arg1, arg2, arg1 + arg2, arg1 * arg2 ) 
        return( ret_val )

This method gives the function "advanced warning" regarding the desired output. Consequently it can skip unneeded processing and only do the work necessary to get your desired output. Also because Python does dynamic typing, the return type can change. Notice how the example returns a scalar, a list or a tuple... whatever you like!

Sepia answered 8/3, 2014 at 20:42 Comment(0)
D
6

If this is a function that you use all the time but always discard the second argument, I would argue that it is less messy to create an alias for the function without the second return value using lambda.

def func():
    return 1, 2

func_ = lambda: func()[0] 

func_()  # Prints 1 
Delectation answered 13/10, 2017 at 14:46 Comment(0)
C
3

When you have many output from a function and you don't want to call it multiple times, I think the clearest way for selecting the results would be :

results = fct()
a,b = [results[i] for i in list_of_index]

As a minimum working example, also demonstrating that the function is called only once :

def fct(a):
    b=a*2
    c=a+2
    d=a+b
    e=b*2
    f=a*a
    print("fct called")
    return[a,b,c,d,e,f]

results=fct(3)
> fct called

x,y = [results[i] for i in [1,4]]

And the values are as expected :

results
> [3,6,5,9,12,9]
x
> 6
y
> 12

For convenience, Python list indexes can also be used :

x,y = [results[i] for i in [0,-2]]

Returns : a = 3 and b = 12

Carcinoma answered 18/10, 2017 at 20:37 Comment(0)
L
1

It is possible to ignore every variable except the first with less syntax if you like. If we take your example,


# The function you are calling.
def func():
    return 1, 2

# You seem to only be interested in the first output.
x, temp = func()

I have found the following to works,

x, *_ = func()

This approach "unpacks" with * all other variables into a "throwaway" variable _. This has the benefit of assigning the one variable you want and ignoring all variables behind it.

However, in many cases you may want an output that is not the first output of the function. In these cases, it is probably best to indicate this by using the func()[i] where i is the index location of the output you desire. In your case,

# i == 0 because of zero-index.
x = func()[0]

As a side note, if you want to get fancy in Python 3, you could do something like this,

# This works the other way around.
*_, y = func()

Your function only outputs two potential variables, so this does not look too powerful until you have a case like this,

def func():
    return 1, 2, 3, 4

# I only want the first and last.
x, *_, d = func()
Lunitidal answered 16/12, 2022 at 22:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.