41

Is there any recommended/generally accepted coding style for handling situations where a function returns a tuple of values but only one of those values is used afterwards (note that this is mostly meant for library functions I can't change -- writing a wrapper around the call is probably a bit of overkill…)? Instead of doing

a, b, c = foo()

and then just not using b and c, which of the following variants should be preferred (or is there another one?):

Variant 1 (underscore)

a, _, _ = foo()

(which is very clear and simple but might clash with _ = gettext.gettext used in many applications that use translation)

Variant 2 (dummy name)

a, unused, unused = foo()

(not very appealing, I think, same goes for other names like dummy)

Variant 3 (index)

a = foo()[0]

(to me the ()[0] looks un-pythonic…)

6
  • It contrast to my former answer, what happens with variant 3 when you now want to reference 2/3 of the return values? I removed my answer because I realised I didn't know enough about Python to justify it.
    – Craige
    Mar 13, 2012 at 18:50
  • @Craige: I did not see your answer before you removed it... Are you asking whether a, b = foo()[0:2] would work? If yes: yes, it does :)
    – user49643
    Mar 13, 2012 at 21:53
  • That was exactly what I was asking. If that works (as you said it does) I'd use variant 3. I'm re-instating my answer given this information.
    – Craige
    Mar 14, 2012 at 2:40
  • 3
    Incidentally, these days you can use the rather beautiful syntax for 'extended' unpacking: a, *_ = foo() will throw away all the values except the first one. May 29, 2015 at 16:58
  • duplicate of stackoverflow.com/questions/431866/… Jul 9, 2015 at 14:34

6 Answers 6

20

Using the underscore for unused variables is definitely acceptable. Be warned though, in some codebases it's not an option as that identifier is reserved as shorthand for gettext. This is the most frequent objection to this style (though it's not an issue for the majority as far as I can judge). I'd still recommend it, and always use it myself.

Names like dummy or unused tend to irritate me personally, and I don't see them terribly often (in Python, that is - I know a Delphi codebase which uses dummy liberally, and it has also leaked into scripts associated with the program in question). I'd advice you against it.

Just extracting one item from the returned tuple is okay too. It also saves some hassle with getting the number of unused values right. Note though that it's has two potential downsides:

  • It doesn't blow up if the number of values is different from what you expect. This may be useful to detect mixups and typos.
  • It only works when the return value is a sequence (that's mostly tuples and lists, but let's stay general). Offhand, I know one class in my code (a 2D vector) that is iterable and yields a constant number of values (and thus can be used in unpacking assignments), but is not indexable.
2
  • I did actually mention gettext in my question :) Anyway, I accepted your answer -- it seems that there is no clear single accepted style but your answer raised some interesting points.
    – user49643
    Mar 15, 2012 at 13:58
  • To avoid problems with gettext (or to avoid similar problems in the interpreter) you can use double underscores (aka dunders) instead of the single.
    – Zim
    Sep 5, 2019 at 20:10
29

Pylint has gotten me in the habit of doing it this way:

widget, _parent, _children = f()

That is, unused results have a descriptive name prefixed by _. Pylint regards locals prefixed with _ as unused, and globals or attributes prefixed with _ as private.

4

As others have said, underscore (_) is the standard. But if underscore is being used for translations, I think double underscore is the best alternative.

var, __, value = "VAR=value".partition('=')

Better than these:

var, unused, value = "VAR=value".partition('=')

var, unused_del, value = "VAR=value".partition('=')

var, _del, value = "VAR=value".partition('=')

3

If in your entire project, you're only doing this this once or very rarely wrt the particular function, I would use Variant 1 if you know gettext isn't a problem in that module, and otherwise Variant 3.

On the other hand, if you were doing this a lot - and especially if each time you want a different subset of the return values (making a wrapper to just return the ones you care about unviable), it might be beneficial to write a wrapper that puts the results into a named tuple, or an instance of some other descriptive class, which would let you do:

bar = foo()

And then work with bar.a, bar.b and bar.c.

1

I'm a non-Python programmer, but to me the third variant makes the most sense.

In variant 3 you are absolutely clear which values your are interested in dealing with. In variant 1 and 2, you are assigning the values back to variables, and thus, they can be used. You may have named them obscurely, but poor naming isn't really a solution to any problem.

Aside from clarity, why would you want to assign unused values to a slot in memory (as in variants 1 and 2)? This would be a poor solution in terms of memory management.

1
  • If you always put it on the same variable wouldn't the memory problem be only the size of a single variable at any given time? I don't think that should be an issue.
    – giraffesyo
    Apr 15, 2017 at 22:38
-2

Here's a general rule: If only 1 of the returned values is used, why not simply return that 1 value? In case the flag is being called from multiple places, keep a flag for the same and return values as per the flag.

EDIT:

In case I was in your situation, and I hadn't written the function, I'd perhaps go for Variant 2. I'd keep the dummy names there so that the parameters can be used in case need arises. Slicing a list will have a little overhead. Perhaps you can spare a few bytes to receive the unwanted data.

4
  • -1 I'm guessing he didn't define the function, and thus can't change what it returns. I think he's referring to when the function returns 3 values, but he only cares about 1 in his current use-case.
    – Craige
    Mar 13, 2012 at 18:31
  • @Craige: Yes, I meant functions I could not change -- I added a note to my question clarifying that.
    – user49643
    Mar 13, 2012 at 18:33
  • Are you sure about the overhead? I tried a very simple ipython test: %timeit a, _, _ = foo() vs. %timeit a = foo()[0] which resulted in 123ns vs. 109ns, i.e. the slicing seems to be actually faster than the value unpacking. Or did you have any specific situation in mind?
    – user49643
    Mar 13, 2012 at 21:50
  • 2
    Another plausible scenario is that you don't need all the values for some calls. Mar 14, 2012 at 0:59

Not the answer you're looking for? Browse other questions tagged or ask your own question.