Skip to content

gh-151907: Avoid creating temporary objects in some comprehensions#151908

Open
ZeroIntensity wants to merge 7 commits into
python:mainfrom
ZeroIntensity:comprehension-avoid-creation
Open

gh-151907: Avoid creating temporary objects in some comprehensions#151908
ZeroIntensity wants to merge 7 commits into
python:mainfrom
ZeroIntensity:comprehension-avoid-creation

Conversation

@ZeroIntensity

@ZeroIntensity ZeroIntensity commented Jun 22, 2026

Copy link
Copy Markdown
Member

The following code:

[i for i in range(42)]

is essentially turned into:

for i in range(42):
    pass

Comment thread Python/codegen.c
VISIT(c, expr, elt);
ADDOP(c, elt_loc, POP_TOP);
break;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we instead just wrap the LIST_APPEND in if !avoid_creation?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we'd also need to wrap the LIST_EXTEND with that too; I opted for this approach to avoid duplicating that logic.

But do we need the separate VISIT path for the Starred case at all? I might be able to refactor it to look like this:

ISIT(c, expr, elt);
if (elt->kind == Starred_kind) {
    op = LIST_EXTEND;
}
else {
    op = LIST_APPEND;
}
if (!avoid_creation) {
    ADDOP_I(c, elt_loc, op, depth + 1);
}

@iritkatriel

Copy link
Copy Markdown
Member

I think this might change semantics for the dict case - if a key is not hashable.

@ZeroIntensity

Copy link
Copy Markdown
Member Author

Yeah, good catch. This breaks set too:

{x for x in [[]]}  # No error!

I'll just remove set and dict for now, but it might still be possible to avoid object creation by calling PyObject_Hash. Not worth doing that here though.

This was a breaking change because hash() was no longer called on the
elements.
@iritkatriel

Copy link
Copy Markdown
Member

Yeah, good catch. This breaks set too:

{x for x in [[]]}  # No error!

I'll just remove set and dict for now, but it might still be possible to avoid object creation by calling PyObject_Hash. Not worth doing that here though.

Maybe also add tests for these cases.

]
self.codegen_test(snippet, expected)

def test_no_target_comp_optimization(self):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you need to add a test where the loop body has a side effect. IIUC, the body with thread.join() should be turned into a method call, rather than just pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants