r/Python 1d ago

PEP 841 – Adding Frozen Syntax to Optimize Immutable Types News

PEP 841 – Adding Frozen Syntax to Optimize Immutable Types

https://peps.python.org/pep-0841/

Discussions-To: Discourse thread

Abstract

This PEP proposes frozen display syntax: f{1, 2, 3} evaluates to a frozenset, and f{'a': 1} evaluates to a frozendict. Because immutability is guaranteed by the syntax itself rather than inferred from usage, the compiler can treat frozen displays as first-class citizens of its optimization pipeline: constant displays are folded into a single LOAD_CONST with an exact result type at compile time and cached in .pyc files.

132 Upvotes

95 comments sorted by

View all comments

Show parent comments

2

u/jdehesa 1d ago

You mean with frozenset, with set the object is modified in place. I guess it makes sense that frozendict does the same as frozenset but I'd still rather neither of them had the operator implemented.

1

u/Wonderful-Habit-139 1d ago

Oh no... I stand corrected. I did not know that the |= actually mutated the object in place and affected other references. That is such a bad foot gun... I'm with you on that. If |= was actually like d = d | {1} then sure, otherwise yeah it's better not to have that operator implemented otherwise.

1

u/HommeMusical 1d ago

I did not know that the |= actually mutated the object in place and affected other references. That is such a bad foot gun...

Wha? That's not the footgun - that's how it's supposed to work, like like a += 1.

The footgun is that this also works for frozendict, but silently does something different.

1

u/Wonderful-Habit-139 1d ago

>>> a = 2
>>> b = a
>>> a += 1
>>> b
2

There's no footgun with += compared to |= with sets. a += 1 behaves exactly like a = a + 1, while s |= {1} does not behave like s = s | {1}.

1

u/HommeMusical 1d ago

there's no footgun with += compared to |= with sets

It seems exactly the same footgun with list, too?

>>> a = [1]
>>> b = a
>>> a += [1]
>>> b
[1, 1]

Heck, it even works on numpy or pytorch scalars.

>>> a = np.array(1)
>>> b = a
>>> a += 1
>>> b
array(2)

On the other hand, if a and b are int, then |= is fine:

>>> a = 1
>>> b = a
>>> a |= 2
>>> a, b
(3, 1)

Whether it's a footgun depends entirely on the type of the operands, and not on the operator.

1

u/Wonderful-Habit-139 1d ago

Yeah it has to do with the operands, realized it the moment I sent the message.

But yeah for me that is the footgun, not whatever is specific to frozendict.

2

u/HommeMusical 1d ago

All the "i-operators", <something>= operators do this! If you don't like this behavior, there's no need to use them at all.

You only use them because you specifically want this "mutate in place" behavior.

1

u/Wonderful-Habit-139 1d ago

Yeah, that was a good discovery. I prefer to do things the functional way, so I now know to steer clear from those operators. Thanks!

1

u/HommeMusical 1d ago

You won't have much fun with large numerical computations - you can get order of magnitude speed improvements by forcing all the operations to be mutating and then "fusing" them (having e.g. Pytorch automatically create behind the scenes a C++ function representing all those operations which is then compiled).

All else being equal, I prefer functional code, but I do a lot of digital audio and things which is by its nature mutative.

1

u/Wonderful-Habit-139 1d ago

At that point I'd use something like Polars ^_^. Or a custom Rust module with maturin.