Skip to content

Avoid construction of objects in comprehensions without targets #151907

Closed

Description

@ZeroIntensity

Feature or enhancement

This is quite a silly micro-optimization.

For context, I ended up in a discussion about whether code like the following is a good idea:

[thread.join() for thread in threads]

Some people like the brevity over an explicit loop. The primary argument against this pattern is that this has the additional overhead of creating an additional list object (or set object for set comprehensions, dict for dict comprehensions). That made me wonder whether it was possible to simply omit the construction when the comprehension isn't used as a value. I managed to come up with a relatively small patch.

To be clear, I don't think this should be interpreted as an endorsement of this pattern. I, and probably many others, believe that for thread in threads: thread.join() is the better option, but that's beside the point; there are definitely people who do this in practice, and I think they'll enjoy the minor speedup.

Linked PRs

Activity

  1. terryjreedy commented on Jun 22, 2026

    @terryjreedy
    Member

    This breaks the simple rule that an expression statement evaluates the expression to a value and tosses it or prints it depending on the input mode.

    Why only for list comps and not set comps? Or for other side-effect only expressions? This will like confuse people.

    Some people like the brevity over an explicit loop.

    The explicit loop is one character shorter. People are typing an extra character to misuse an expression.

    I don't think this should be interpreted as an endorsement of this pattern.

    To me it is, and at least some people will interpret this as so and even teach it as something to do.

  2. ZeroIntensity commented on Jun 22, 2026

    @ZeroIntensity
    MemberAuthor

    This breaks the simple rule that an expression statement evaluates the expression to a value and tosses it or prints it depending on the input mode.

    I wouldn't go as far to say that's a "rule" -- we do this kind of optimization for constants already. A blank 42 with no target is optimized away at compile-time (and I'd think there are significantly fewer people doing this than people using the comprehension pattern).

    Why only for list comps and not set comps? Or for other side-effect only expressions? This will like confuse people.

    1. I tried doing this for set/dict comprehensions as well, but it ended up breaking things because hash was no longer called on the elements.
    2. I think we should optimize other ones as well, but this one stuck out to me because people are actually doing this in practice. I can't think of a time where we've rejected an optimization on the basis that "there are similar things that aren't optimized yet".
    3. I would be very surprised if anyone actually noticed the difference, and if they actually cared. I've only ever seen people do a bare list comprehension in the wild, and that's a small minority already. I'd be shocked if that small minority were to also do this for sets or dicts, and then look at the bytecode for inconsistencies. People just don't look at bytecode disassembly and compare random expressions.

    The explicit loop is one character shorter.

    I think the appeal is that it's all on one line, but that's beside the point; people are doing this anyway.

    To me it is, and at least some people will interpret this as so and even teach it as something to do.

    I doubt this optimization will actually sway opinions. The people who were doing this already will continue doing this, and the people who weren't will continue to not. People care more about the aesthetics than the speed, but I just think that CPython should be aware of both cases when optimizing.

    More generally, I don't think we should only optimize things that we consider "good practice". We should aim to produce fast results, even if the code to produce those results was bad.

  3. added a commit that references this issue on Jul 14, 2026
  4. added a commit that references this issue on Jul 28, 2026
  5. added a commit that references this issue on Sep 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)performancePerformance or resource usagetopic-parsertype-featureA feature request or enhancement

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions