You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Remove performance penalty of ast.unparse(ast.Set(elts=[])) ({*()} can be used in advanced cases and will not change recommended way to write empty set set())
Remove performance penalty of incremental construction between 0-to-1/1-to-0 elements for set and tuple literals without special case considerations (e.g. x = *(), pre-seeded tuple literal without trailing comma pitfall)
Keep implementation in simple/self-contained in bytecode generation, avoiding any AST changes to language
Near-zero performance impact to bytecode generation (improves subsequent bytecode optimizations of target case)
xychart-beta
title "Compile targeted mean ratio vs main"
x-axis [Main, Flowgraph, Leading]
y-axis "Ratio" 0 --> 1.01
bar [1.000, 0.963, 0.948]
Loading
Control near-miss case comparisons moved less than +/-1% and are attributed to noise.
Runtime
The set() versus {*()} comparison is especially useful because it changes qualitatively across the two branches (~6.3% slower to ~29.5% faster):
Branch
set() mean (ns)
{*()} mean (ns)
{*()} vs set()
Main
54.14
57.53
1.063x
Flowgraph only
53.49
38.01
0.711x
Codegen leading only
55.44
39.00
0.704x
Before this change, {*()} was paying for a redundant empty update and ended up slower than the constructor call. After the change, {*()} compiles down to a direct BUILD_SET 0; RETURN_VALUE path, while set() still has to load the global and perform a zero-argument call.
Has this already been discussed elsewhere?
I have already discussed this feature proposal on Discourse
Feature or enhancement
Proposal:
Performance was discussed at various times within PEP 802 topic, submitting this proposal as the PEP is unlikely to be accepted.
Goal:
ast.unparse(ast.Set(elts=[]))({*()}can be used in advanced cases and will not change recommended way to write empty setset())setandtupleliterals without special case considerations (e.g.x = *(),pre-seeded tuple literal without trailing comma pitfall)Implementation examples:
Micro-benchmark
Run on windows x64bit release build: empty_unpack_benchmark.py
Compile time
Targeted cases:
[*()]{*()}(*(),)x = *(),Control near-miss case comparisons moved less than +/-1% and are attributed to noise.
Runtime
The
set()versus{*()}comparison is especially useful because it changes qualitatively across the two branches (~6.3% slower to ~29.5% faster):set()mean (ns){*()}mean (ns){*()}vsset()Before this change,
{*()}was paying for a redundant empty update and ended up slower than the constructor call. After the change,{*()}compiles down to a directBUILD_SET 0; RETURN_VALUEpath, whileset()still has to load the global and perform a zero-argument call.Has this already been discussed elsewhere?
I have already discussed this feature proposal on Discourse
Links to previous discussion of this feature:
https://discuss.python.org/t/pep-802-display-syntax-for-the-empty-set/101676/237
https://discuss.python.org/t/pep-802-display-syntax-for-the-empty-set/101676/216
https://discuss.python.org/t/pep-802-display-syntax-for-the-empty-set/101676/3