Identity fast path for * 1 on immutable types
Currently, multiplying by 1 on numeric types creates a new object and goes through the full multiplication code path, despite being a no-op semantically:
$ ./python.exe -m timeit -s 'a=1e9' 'a * 1'
10000000 loops, best of 5: 31.3 nsec per loop
For immutable types, x * 1 could simply return x — no new allocation, no arithmetic.
Motivation
A common pattern involves a scaling constant that is frequently 1:
seq = list(range(10))
lb = 4
ub = 8
scale = 2
scaled_seq = [x for x in seq for _ in range(scale)]
for _ in range(1e9):
idx = do_something(scaled_seq, lb * scale, ub * scale)
# scale back
idx //= scale
do_something_with_original(seq, idx)
When scale == 1, all multiplication and allocation is pure overhead. An identity check before the multiply would eliminate it with no branching cost.
Type candidates
int — straightforward
tuple - straightforward
float — needs to handle NaN * 1 correctly per IEEE 754 (must still return a new NaN)
Decimal / Fraction — most expensive to construct, largest potential win, may have edge case nuances
Identity fast path for
* 1on immutable typesCurrently, multiplying by
1on numeric types creates a new object and goes through the full multiplication code path, despite being a no-op semantically:For immutable types,
x * 1could simply returnx— no new allocation, no arithmetic.Motivation
A common pattern involves a scaling constant that is frequently
1:When
scale == 1, all multiplication and allocation is pure overhead. An identity check before the multiply would eliminate it with no branching cost.Type candidates
int— straightforwardtuple- straightforwardfloat— needs to handleNaN * 1correctly per IEEE 754 (must still return a newNaN)Decimal/Fraction— most expensive to construct, largest potential win, may have edge case nuances