778

What is the meaning of _ after for in this code?

if tbh.bag:
    n = 0
    for _ in tbh.bag.atom_set():
        n += 1
Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
alwbtc
  • 28,057
  • 62
  • 134
  • 188

5 Answers5

989

_ has 3 main conventional uses in Python:

  1. To hold the result of the last executed expression in an interactive interpreter session (see docs). This precedent was set by the standard CPython interpreter, and other interpreters have followed suit

  2. For translation lookup in i18n (see the gettext documentation for example), as in code like

    raise forms.ValidationError(_("Please enter a correct username"))
    
  3. As a general purpose "throwaway" variable name:

    1. To indicate that part of a function result is being deliberately ignored (Conceptually, it is being discarded.), as in code like:

      label, has_label, _ = text.partition(':')
      
    2. As part of a function definition (using either def or lambda), where the signature is fixed (e.g. by a callback or parent class API), but this particular function implementation doesn't need all of the parameters, as in code like:

      def callback(_):
          return True
      

      [For a long time this answer didn't list this use case, but it came up often enough, as noted here, to be worth listing explicitly.]

    This use case can conflict with the translation lookup use case, so it is necessary to avoid using _ as a throwaway variable in any code block that also uses it for i18n translation (many folks prefer a double-underscore, __, as their throwaway variable for exactly this reason).

    Linters often recognize this use case. For example year, month, day = date() will raise a lint warning if day is not used later in the code. The fix, if day is truly not needed, is to write year, month, _ = date(). Same with lambda functions, lambda arg: 1.0 creates a function requiring one argument but not using it, which will be caught by lint. The fix is to write lambda _: 1.0. An unused variable is often hiding a bug/typo (e.g. set day but use dya in the next line).

    The pattern matching feature added in Python 3.10 elevated this usage from "convention" to "language syntax" where match statements are concerned: in match cases, _ is a wildcard pattern, and the runtime doesn't even bind a value to the symbol in that case.

    For other use cases, remember that _ is still a valid variable name, and hence will still keep objects alive. In cases where this is undesirable (e.g. to release memory or external resources) an explicit del name call will both satisfy linters that the name is being used, and promptly clear the reference to the object.

ncoghlan
  • 40,168
  • 10
  • 71
  • 80
  • 24
    Could you explain how it works in a function call, for example: **raise forms.ValidationError(_("Please enter a correct username"))**. I've seen this in Django code, and it's not clear what's going on. – John C May 19 '11 at 13:43
  • 44
    That is usage 2 - by convention, `_` is the name used for the function that does internationalisation and localisation string translation lookups. I'm pretty sure it is the C `gettext` library that established that convention. – ncoghlan May 19 '11 at 16:47
  • 50
    FWIW, I've personally started using ``__`` (a double underscore) as my general purpose throwaway variable to avoid conflicting with either of the first two use cases. – ncoghlan Mar 20 '12 at 06:35
  • This use of a single `_` as a variable name for a throwaway variable isn't mentioned in PEP 8. Do you know of an authoritative source that suggests using it for that purpose? – martineau Jun 23 '15 at 19:30
  • 17
    Emergent community conventions don't tend to have authoritative sources - just observations of the practices that have appeared over time. FWIW, I'm one of the co-authors of more recent PEP 8 updates, and my answer is based on the 3 different ways I've seen `_` used as a variable name since I started using Python professionally in 2002. – ncoghlan Jun 28 '15 at 03:54
  • 1
    Thanks for the answer. Anyway I do not understand the advantage of marking a variable as not used. On the contrary, since one of the goals of Python is to let you make readable code, IMHO the use of the underscore character as variable or function name is not a good idea. – Marco Sulla Feb 25 '16 at 13:18
  • 14
    The convention is mainly for tuple unpacking: `a, __, c = iterable` tells the reader immediately that we're unpacking a 3-tuple, but only using the first and last values. If we instead write `a, b, c = iterable`, the reader (or an automated code linter) can reasonably expect all of `a`, `b`, and `c` to be used later (and if they're not, it may be a sign of a bug somewhere). – ncoghlan Feb 29 '16 at 07:42
  • An example of the *implementation* of `_` for number 2 might be helpful here. Or would that be better addressed in another question? I'm not sure how to ask such a question if so. – jpmc26 Feb 21 '17 at 01:33
  • 2
    @jpmc26: I added a link to the most immediately relevant part of the stdlib gettext docs: https://docs.python.org/3/library/gettext.html#localizing-your-module (there are higher level il8n modules out there, but this particular convention came from the C `gettext` API, and Python adopted it from there) – ncoghlan Mar 02 '17 at 09:35
  • 2
    It seems to be also used for separating digits in number? `>>> 1_000_123` results in `1000123` – Miserable Variable Jun 05 '17 at 23:44
  • 2
    @MiserableVariable That's a new feature added in 3.6 for writing numeric literals, and it doesn't involve `_` being used as a *variable*. It's closer to using it as part of a larger identifier like `functools.total_ordering` or `contextlib.redirect_stdout`. – ncoghlan Jun 07 '17 at 05:49
  • @ncoghlan I am very new to Python. I found your excellent answer (I found something new, how to access the last expression statement) while searching for underscore meaning. It is not a variable, but I do think it falls under (or will become) one of "main conventional uses in Python". Given the popularity of your answer I think it will be a good point to add for future visitors. – Miserable Variable Jun 08 '17 at 20:50
  • @MiserableVariable That's the first use case listed (and it is a normal variable - it's just implicitly bound by the interactive loop). However, I've updated it to say "expression(/statement)" rather than just "statement". – ncoghlan Jun 23 '17 at 07:31
  • 2
    Consider extending a bit your answer for function parameters, so we can redirect here from questions like these: [Python's lambda with no variables?](https://stackoverflow.com/questions/29767310/pythons-lambda-with-no-variables), [Python underscore as a function parameter](https://stackoverflow.com/questions/5787277/python-underscore-as-a-function-parameter) or more recent [What does "_" mean in lambda function?](https://stackoverflow.com/questions/57197032/what-does-mean-in-lambda-function-and-why-is-it-used) – Georgy Jul 25 '19 at 09:58
  • 1
    @Georgy Done! It still doesn't cover https://stackoverflow.com/questions/5787277/python-underscore-as-a-function-parameter though, as the `hexdump(_)` case must be getting a value from *somewhere*, since it's a function call, rather than a function definition. – ncoghlan Aug 07 '19 at 04:18
  • eg. from the argparse.py library: `from gettext import gettext as _`. Once you know, you know, I guess, but not exactly 'pythonic' ie. obvious, until you do. – Ed Randall May 27 '20 at 06:20
  • 1
    note: added lint use case, 9 years after the answer was originally written. – user5994461 Jul 04 '20 at 18:59
  • @user5994461 As you noted in the edit, linting is technically covered by the original 3 listed use cases. Listing it separately makes sense though, since the motivation is a bit different (eliminating a warning from a tool, rather than communicating with a reader, even though abiding by the convention helps readers as well) – ncoghlan Jul 15 '20 at 08:25
  • Note `_` can also be used as `1_500_500` which is `1500500`. – wyz23x2 Aug 19 '20 at 12:53
  • 1
    @ncoghlan --- I know it's many years later, but it may be worth making clear that even though it is, as you say, "conceptually" discarding, the variable still exists and consumes memory in its scope. So if you have `a, _ = really_large_second_element()`, the `_` will continue sitting in memory until garbage collection kicks in during a context change and refcount goes to zero. I've never considered this until dealing with big data workflows. Now, I explicitly assign to a throwaway variable and `del` it: `a, throwaway = really_large_second_element()` then `del throwaway` – randomusername Sep 24 '21 at 17:35
  • @tloveless Why bother saving it in the first place? `a = really_large_second_element()[0]`. Or for iterators, `a = next(really_large_second_element())`. For more complicated cases, you can use tools like [`itertools.islice()`](https://docs.python.org/3/library/itertools.html#itertools.islice). – wjandrea Sep 24 '21 at 18:27
  • 1
    @wjandrea -- sure, we could use various tools to accomplish different patterns. I was simply pointing out that the idea of "conceptually" throwing something away doesn't mean you're actually doing so. Also, something like `a, X, b, X = unpackable()` followed by a `del X` is quite readable, and won't suffer any more than simply not returning whatever value would have been returned from `unpackable`, presuming `unpackable` holds X in memory anyway. – randomusername Sep 25 '21 at 20:09
  • Adjusted the answer to both mention 3.10's pattern matching (which doesn't bind `_` wildcard patterns at all), and that in other contexts, even `_` is still a valid reference that keeps objects alive. – ncoghlan Oct 12 '21 at 07:21
  • You can also use `a, b, *_, c = (1, 2, 3, 4, 5, 6, 7)` if your goal is to only use the first, second, and last items. The throwaway `_` in this case is `[3, 4, 5, 6]` – Levi Baguley Oct 14 '21 at 21:16
  • @ncoghlan. So I just saw code of the form `x = [foo(_) for _ in range(10)]`. This is a slightly different version: "This variable is too irrelevant and too short-lived to bother giving a real name to it." Would this be considered acceptable to seasoned Python programmers? Are the meaning(s) of _ just conventional, or are they in some PEP? – Frank Yellin Jun 27 '23 at 17:10
  • @Frank I wouldn't use that. The point of a throwaway name is to indicate that it's only assigned to, never used. So using it is surprising/confusing. For that example, I would do `list(map(foo, range(10)))` instead, which does the same thing but doesn't use any name at all. – wjandrea Jun 27 '23 at 21:24
  • @wjandrea. I wouldn't use it either. I saw it in some code I was looking at and didn't know whether this within reason or not. (And the actual code had a slightly more complicated functional call, so a straightforward `map` wouldn't work.) – Frank Yellin Jun 27 '23 at 21:30
  • @Frank In that case I'd use something super generic, like `[foo(i) for i in range(10)]` – wjandrea Jun 27 '23 at 21:31
252

It's just a variable name, and it's conventional in python to use _ for throwaway variables. It just indicates that the loop variable isn't actually used.

gsteff
  • 4,764
  • 1
  • 20
  • 17
  • 7
    you mean it doesn't represent the last returned value? – alwbtc May 05 '11 at 05:52
  • 40
    @steve only in a python _shell_ – Gabi Purcaru May 05 '11 at 05:55
  • 4
    similar to the use of _ in Prolog – Matthias Feb 23 '16 at 09:19
  • 5
    similar to the use of ~ in Matlab – PatriceG Apr 25 '17 at 13:42
  • 2
    Note that in the cpython shell if you explicitly define `_`, it permanently stops holding the output value of the previous expression. This seems horribly inconsistent, and the Python lang standards need to address this. They should just define `_` to be a throwaway name and stop it from being used as a real identifier. – theferrit32 Apr 01 '20 at 18:38
  • @theferrit32 It's not permanent at all. Check out [my answer on "How do I reset the underscore in an interactive session?"](/a/70491458/4518341). – wjandrea Feb 26 '23 at 18:26
131

Underscore _ is considered as "I don't Care" or "Throwaway" variable in Python

  • The python interpreter stores the last expression value to the special variable called _.

    >>> 10 
    10
    
    >>> _ 
    10
    
    >>> _ * 3 
    30
    
  • The underscore _ is also used for ignoring the specific values. If you don’t need the specific values or the values are not used, just assign the values to underscore.

    Ignore a value when unpacking

    x, _, y = (1, 2, 3)
    
    >>> x
    1
    
    >>> y 
    3
    

    Ignore the index

    for _ in range(10):     
        do_something()
    
Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
Ashish25
  • 1,965
  • 1
  • 15
  • 16
  • 3
    There's a third usage, which is for the internationalization function `_("Hello world!")`. – Jeff Younker Mar 14 '18 at 09:52
  • 11
    At the processor level, is there actually difference between "for _ in range" and "for x in range" and then not using x? Or is it just for human readability? – iammax Jul 11 '18 at 16:42
  • 10
    @iammax Using the `dis` module I found there was no difference in the bytecode. The benefits of human readability are obvious, however. – Alistair Carscadden Sep 07 '18 at 08:36
  • Why if I `print` something it doesn't show this value? – ado sar Jan 22 '23 at 11:46
  • 1
    @ado What do you mean? What are you printing, and what are you expecting to see exactly? If you do `>>> 10` then `>>> print(_)`, 10 will be printed, if that's what you mean. – wjandrea Jun 27 '23 at 21:17
32

There are 5 cases for using the underscore in Python.

  1. For storing the value of last expression in interpreter.

  2. For ignoring the specific values. (so-called “I don’t care”)

  3. To give special meanings and functions to name of variables or functions.

  4. To use as ‘internationalization (i18n)’ or ‘localization (l10n)’ functions.

  5. To separate the digits of number literal value.

Here is a nice article with examples by mingrammer.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
Reck
  • 1,388
  • 11
  • 20
  • 2
    In fact it's pretty new https://www.blog.pythonlibrary.org/2017/01/11/new-in-python-underscores-in-numeric-literals/ – MichaelChirico Sep 19 '18 at 15:23
  • 2
    Numbers 3 and 5 don't really apply to this question. OP's asking about a single underscore as a standalone name, but point 3 talks about using underscores as part of a bigger name, and point 5 talks about using it in a literal, not a name. I'm just mentioning in case any newbies are confused. It might help to [edit] the answer to clarify it. – wjandrea Nov 26 '20 at 18:41
13

As far as the Python languages is concerned, _ generally has no special meaning. It is a valid identifier just like _foo, foo_ or _f_o_o_.
The only exception are match statements since Python 3.10:

In a case pattern within a match statement, _ is a soft keyword that denotes a wildcard. source

Otherwise, any special meaning of _ is purely by convention. Several cases are common:

  • A dummy name when a variable is not intended to be used, but a name is required by syntax/semantics.

    # iteration disregarding content
    sum(1 for _ in some_iterable)
    # unpacking disregarding specific elements
    head, *_ = values
    # function disregarding its argument
    def callback(_): return True
    
  • Many REPLs/shells store the result of the last top-level expression to builtins._.

    The special identifier _ is used in the interactive interpreter to store the result of the last evaluation; it is stored in the builtins module. When not in interactive mode, _ has no special meaning and is not defined. [source]

    Due to the way names are looked up, unless shadowed by a global or local _ definition the bare _ refers to builtins._ .

    >>> 42
    42
    >>> f'the last answer is {_}'
    'the last answer is 42'
    >>> _
    'the last answer is 42'
    >>> _ = 4  # shadow ``builtins._`` with global ``_``
    >>> 23
    23
    >>> _
    4
    

    Note: Some shells such as ipython do not assign to builtins._ but special-case _.

  • In the context internationalization and localization, _ is used as an alias for the primary translation function.

    gettext.gettext(message)

    Return the localized translation of message, based on the current global domain, language, and locale directory. This function is usually aliased as _() in the local namespace (see examples below).

wjandrea
  • 28,235
  • 9
  • 60
  • 81
MisterMiyagi
  • 44,374
  • 10
  • 104
  • 119