# PEP 841: Adding Frozen Syntax to Make Immutable Types Optimizable

**URL:** <https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219>\
**Category:** PEPs\
**Created:** [July 20, 2026, 2:55am UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219 "2026-07-20T02:55:49Z")\
**Posts on this page:** 20\
**Page:** 3

<div class="post-metadata">

**Author:** ![kapinga](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/kapinga/32/24087_2.png) [@kapinga](https://discuss.python.org/u/kapinga)\
**Post date:** [July 21, 2026, 1:26am UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219/42 "2026-07-21T01:26:14Z")

</div>

> [@timhoffm](#):
>
> If a data type is important enough to be a builtin, it’s a strong candidate for also having a literal syntax.

This is an interesting way of framing the motivation. Looking at the class constructors amongst the [3.15 built ins](https://docs.python.org/3.15/library/functions.html):

```python
bool()
bytearray()
bytes()
complex()
dict()
float()
frozendict()
frozenset()
int()
list()
memoryview()
object()
property()
range()
set()
sentinel()
slice()
str()
super()
tuple()
type()

```

Of these: `bool`, `bytes`, `complex`, `dict`, `float`, `int`, `list`, `set`, `str`, and `tuple` have existing display syntax. `slice` also has dedicated syntax, albeit technically not a display. `memoryview`, `object`, `property`, `sentinel`, `super`, and `type` largely don’t make sense as displays (for varying reasons).

That leaves `bytearray`, `frozendict`, `frozenset` and `range` which _could_ have a meaningful display, but don’t. `bytearray` is particularly interesting as an inversion from the situation posed here: a mutable variant of a more common immutable type. I don’t think anyone is clamoring for `bytearray` displays (except perhaps in an appeal to consistency).

So built in value types frequently, but not always, warrant dedicated syntax (usually a display). It’s a point in favor of making `frozenset` and `frozendict` displays, but certainly not enough on its own.

---

<div class="post-metadata">

**Author:** ![jonathandung](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jonathandung/32/35459_2.png) [@jonathandung](https://discuss.python.org/u/jonathandung)\
**Post date:** [July 21, 2026, 1:43am UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219/43 "2026-07-21T01:43:10Z")

</div>

> the fact you can iterate on a tuple is a design mistake IMO

Sorry if I’m missing something, but how can you unpack a tuple into variables in an assignment if it is not iterable?

---

<div class="post-metadata">

**Author:** ![corona10](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/corona10/32/9943_2.png) [@corona10](https://discuss.python.org/u/corona10)\
**Post date:** [July 21, 2026, 2:22am UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219/44 "2026-07-21T02:22:20Z")

</div>

> [@ncoghlan](#):
>
> I haven’t really decided how I feel about the PEP as a whole yet (which means I’m somewhere between -0 and +0), but one specific “not OK” on a technical detail:

Thank you for pointing this out. We need to update this and preserve the current ordering guarantees.  
cc @sobolevn

---

<div class="post-metadata">

**Author:** ![kapinga](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/kapinga/32/24087_2.png) [@kapinga](https://discuss.python.org/u/kapinga)\
**Post date:** [July 21, 2026, 2:24am UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219/45 "2026-07-21T02:24:58Z")

</div>

I’m +1 on the idea of `frozendict` and `frozenset` having display syntax, but am +0 on the PEP as is.

The motivation and framing (even the title) are too heavily focused on optimization and undersell other reasons to want this (such as making immutable collection types first-class equals with mutable ones). Steve landed a number of valid criticisms regarding how valuable such optimizations will be in practice; bringing in other motivations will strengthen the PEP overall.

I also dislike the syntax, for two reasons:

1. It overloads the meaning of the “f”-prefix (and no, claiming that f-strings are also “frozen” doesn’t fly; all strings are frozen).
2. Braces, particularly when used to define sets and dicts, are conceptually much closer to brackets and parentheses than to quotation marks. Yet letters “prefixing” parentheses and brackets have a _very_ different meaning than what is proposed here.

While I have some thoughts on alternative syntax options, I’ll refrain from airing them unless the PEP authors are interested in revisiting that topic.

---

<div class="post-metadata">

**Author:** ![corona10](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/corona10/32/9943_2.png) [@corona10](https://discuss.python.org/u/corona10)\
**Post date:** [July 21, 2026, 2:42am UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219/46 "2026-07-21T02:42:12Z")

</div>

> [@kapinga](#):
>
> The motivation and framing (even the title) are too heavily focused on optimization and undersell other reasons to want this (such as making immutable collection types first-class equals with mutable on

I think this is a valid criticism. If the PEP currently focuses too heavily on optimization, we are also open to revising its framing. We believe the display syntax is valuable in its own right, while the optimization opportunities are an additional benefit. (Well, I am too biased for this view)  
We can revise the PEP accordingly and then continue the discussion in a second round.

> [@kapinga](#):
>
> While I have some thoughts on alternative syntax options, I’ll refrain from airing them unless the PEP authors are interested in revisiting that topic.

We are open to considering alternative syntax options(then we may need 2nd round discussion for this)

---

<div class="post-metadata">

**Author:** ![corona10](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/corona10/32/9943_2.png) [@corona10](https://discuss.python.org/u/corona10)\
**Post date:** [July 21, 2026, 2:44am UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219/47 "2026-07-21T02:44:47Z")

</div>

> [@corona10](#):
>
> Thank you for pointing this out. We need to update this and preserve the current ordering guarantees.

Revised commit: [PEP 841: Adding Frozen Syntax to Make Immutable Types Optimizable by corona10 · Pull Request #5049 · python/peps · GitHub](https://github.com/python/peps/pull/5049/changes/3506d9bba6fdc33d4079a707943c5e53086d0b2e)

---

<div class="post-metadata">

**Author:** ![blhsing](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/blhsing/32/25812_2.png) [@blhsing](https://discuss.python.org/u/blhsing)\
**Post date:** [July 21, 2026, 4:01am UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219/48 "2026-07-21T04:01:55Z")

</div>

I echo Jon Harding’s sentiments.

> [@corona10](#):
>
> We are open to considering alternative syntax options(then we may need 2nd round discussion for this)

I see in the rejected ideas that the [suggested syntax](https://discuss.python.org/t/frozenset-and-frozendict-comprehensions/101584/32) of `{|'key': 1|}` are rejected because:

1. adding a single token `f{` is easier than adding two tokens, and
2. writing `f{` is also easier than writing two different brackets.

To address both points, how about `{|'key': 1}` instead, so that it adds just one token, and requires writing only one different bracket? The mnemonic will be like `{|` looks like a side view of a shield that shields the content from being modified.

This notation has a side benefit of being possibly extensible to a tuple/frozen list comprehension in the future, e.g. `(|... for _ in range(3))` or `[|... for _ in range(3)]`.

---

<div class="post-metadata">

**Author:** ![BrenBarn](https://avatars.discourse-cdn.com/v4/letter/b/74df32/32.png) [@BrenBarn](https://discuss.python.org/u/BrenBarn)\
**Post date:** [July 21, 2026, 5:24am UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219/49 "2026-07-21T05:24:29Z")

</div>

> [@monk-time](#):
>
> One thing I wish would happen is that people stop blocking things that are important for a (completely valid and popular enough) style of coding they personally don’t use or like.

I just want to push back against this a bit. Things that get into Python — syntax, yes, but also builtins and even the stdlib — become part of what _everyone_ using Python has to be somewhat aware of and conversant with, even if they themselves never use the functionality in questions, because they have to at least be able to read it in code they come across. Personally I most definitely do not want Python to take a “live and let live” attitude in this sense, which would lead to the language becoming a heterogeneous amalgamation of whatever appealed to some subset of users. It’s contrary to the “one obvious way to do it” philosophy.

Now, in the end it depends what appeals to the most people, and if stuff gets in that I don’t personally like I’ll survive\[1\]. But the bar has to be a lot higher than just “some people would find this useful”. The impact on the required level of “reading comprehension” for the community at large has to be considered.

> [@pf\_moore](#):
>
> If it _isn’t_ a goal to encourage more use, then I think having dedicated syntax for relatively infrequently used data types (`frozendfict` isn’t even available in a production version of Python yet!) is questionable.

Even if that is a goal, I still think it’s premature for the reason you gave in your parenthetical remark there. I made a similar comment in the other thread about methods to convert dict to frozendict.

Maybe contrary to some others here I’m not super in love with the idea of “oh this is just a small PEP that makes this one change”. If we want syntax for frozendicts without waiting to see how people use actually frozendicts, that should have been part of the frozendict PEP. We should not “salami slice” changes by introducing one change, and then piling a bunch of other related changes in separate PEPs right away, on the argument that now that Change X made it in, suddenly it justifies changes Y and Z.

Obviously, once a certain change is in place, the community may _after some time_ realize that additional changes are a good idea to support it. But that’s not because the new features _exist_, it’s because we’ve learned through experience how we use them and what the rough edges are. If we know that adding frozendicts will mean we’ll want to add syntax for them, we should do both together; if not, we should wait and see. But in my view the mere fact that a PEP adding frozendicts was accepted has no bearing on whether we should add syntax for them; that change can only be justified after some period of experience with frozendicts.\[2\]

* * *

1. fortunately for me, since it keeps happening over and over! 

2. Even then we should be careful. To my mind, the amount of energy expended on various typing PEPs is an example of how things can go wrong once a “triggering” language change is introduced.

---

<div class="post-metadata">

**Author:** ![timhoffm](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/timhoffm/32/19468_2.png) [@timhoffm](https://discuss.python.org/u/timhoffm)\
**Post date:** [July 21, 2026, 5:34am UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219/50 "2026-07-21T05:34:54Z")

</div>

IMHO adding two tokens is only marginally less easy than two. On the plus side, one can interpret `{|` and `|}` as two-char bracket which gives a nice symmetry, and may be more readable. Generally `{|'key': 1|}` and `{|'key': 1}` are valid candidates.

Maybe we need to first establish that frozen literals are worth it, and have a shortlist of reasonable spellings. That could decouple the discussion of “I don’t like the syntax” from “this is not necessary”. So

- Step 1: Assuming we can find a reasonable spelling (and there a couple of good candidates to give ideas how this could look like), does adding frozenset and frozendict literals add enough benefit?
- Step 2: Discuss the exact spelling. The candidates each have some advantages and disadvantages, which requires careful judgement. `f{}` is one of the good candidates, but locking in on it feels a bit premature.  
Note: The result of this can also be that there is no reasonable spelling, which is arguably the state of the empty set literal discussion.

---

<div class="post-metadata">

**Author:** ![skirpichev](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/skirpichev/32/10996_2.png) [@skirpichev](https://discuss.python.org/u/skirpichev)\
**Post date:** [July 21, 2026, 5:47am UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219/51 "2026-07-21T05:47:11Z")

</div>

> [@sobolevn](#):
>
> Yes, this is my main goal

How this expected to be working?

This is a new syntax, which people will have to learn. Even assuming prior knowledge about frozenset/dict. While, with a same assumption, `frozenset({1, 2, 3})` will be obvious for a reader.

Less characters to type? 🙂

If this is all, I don’t buy it: “code is written once, but read many times” (c). Current state of the language makes using frozen sets/dicts more explicit. And that’s good.

BTW, I think the strongest argument in favor of the PEP — if it will allow some additional optimization, which are _impossible_ (not just _hard_ to do) currently.

---

<div class="post-metadata">

**Author:** ![timhoffm](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/timhoffm/32/19468_2.png) [@timhoffm](https://discuss.python.org/u/timhoffm)\
**Post date:** [July 21, 2026, 5:50am UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219/52 "2026-07-21T05:50:13Z")

</div>

> [@BrenBarn](#):
>
> If we want syntax for frozendicts without waiting to see how people use actually frozendicts, that should have been part of the frozendict PEP. We should not “salami slice” changes by introducing one change, and then piling a bunch of other related changes in separate PEPs right away, on the argument that now that Change X made it in, suddenly it justifies changes Y and Z.

I think this is not quite fair. There is a difference between “salami slice” and keeping the scope focussed. While I was not involved in the PEP-814 discussion, listing frozen literals under the “Deferred Ideas” section to me appears as a measure of focussing: “Adding frozen datatypes is a good idea”. Whether literals are justified as well can be discussed separately, and deferring it from the PEP is neither an argument for or against a follow-up on any timescale.

---

<div class="post-metadata">

**Author:** ![blhsing](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/blhsing/32/25812_2.png) [@blhsing](https://discuss.python.org/u/blhsing)\
**Post date:** [July 21, 2026, 6:20am UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219/53 "2026-07-21T06:20:11Z")

</div>

> [@skirpichev](#):
>
> This is a new syntax, which people will have to learn. Even assuming prior knowledge about frozenset/dict. While, with a same assumption, `frozenset({1, 2, 3})` will be obvious for a reader.
> 
> Less characters to type? 🙂
> 
> If this is all, I don’t buy it: “code is written once, but read many times” (c). Current state of the language makes using frozen sets/dicts more explicit. And that’s good.
> 
> BTW, I think the strongest argument in favor of the PEP — if it will allow some additional optimization, which are _impossible_ (not just _hard_ to do) currently.

To me the benefit is both. For example, I’ve never written:

```python
if item in frozenset({'foo', 'bar', 'baz'}):

```

but instead always write:

```python
if item in {'foo', 'bar', 'baz'}:

```

precisely both because the former is many more characters to type and because it’s less efficient to run.

If a concise frozenset literal is made available I’d gladly switch to it from a set literal.

---

<div class="post-metadata">

**Author:** ![dg-pb](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/dg-pb/32/16248_2.png) [@dg-pb](https://discuss.python.org/u/dg-pb)\
**Post date:** [July 21, 2026, 6:45am UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219/54 "2026-07-21T06:45:02Z")

</div>

> [@kapinga](#):
>
> undersell other reasons to want this (such as making immutable collection types first-class equals with mutable ones)

Yeah, this sounds better - something that sounds more in line with status quo of acceptable motivations that matter.

> [@kapinga](#):
>
> too heavily focused on optimization

But reality is that performance is as important - especially to those who would like to do more and more things with Python and would have to resort to other languages due to performance reasons as little as possible.

Well, I don’t know what proportion of people are in this bracket, but there is definitely one. 🙂

---

<div class="post-metadata">

**Author:** ![timhoffm](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/timhoffm/32/19468_2.png) [@timhoffm](https://discuss.python.org/u/timhoffm)\
**Post date:** [July 21, 2026, 6:53am UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219/55 "2026-07-21T06:53:56Z")

</div>

Performance can only be an added benefit. It’s unlikely that dicts/set are defined in hot loops, and if so and they are constant, they can be pulled out. So performance will aways be just a mirco optimization, not significantly influencing overall program performance.

The real question is: Do we want immutability as a first-class concept that is widely adopted, or is it just for some special cases. Only the intended wide-spread adoption would warrant new syntax with the cost of learning and adaptions in the ecosystem. And conversely, a literal syntax would foster adoption.

---

<div class="post-metadata">

**Author:** ![skirpichev](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/skirpichev/32/10996_2.png) [@skirpichev](https://discuss.python.org/u/skirpichev)\
**Post date:** [July 21, 2026, 7:00am UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219/56 "2026-07-21T07:00:53Z")

</div>

> [@blhsing](#):
>
> precisely both because the former is many more characters to type

Weak argument for me. Perhaps, it does matter for interactive coding in some REPL. Though, even here auto-completion could help and I’m not sure that differences with immutable types are relevant here.

Entirely not relevant for usual coding. Use e_vi_l enough code editor 😉

> [@blhsing](#):
>
> and because it’s less efficient to run

That’s a good argument. _Assuming_ you can convince me, that former case can’t be optimized to avoid a temporary mutable dict, etc.

---

<div class="post-metadata">

**Author:** ![methane](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/methane/32/43_2.png) [@methane](https://discuss.python.org/u/methane)\
**Post date:** [July 21, 2026, 7:44am UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219/57 "2026-07-21T07:44:51Z")

</div>

FWIW, frozenset is used already.

```python
def in_set(x):
    return x in {'foo', 'bar', 'baz'}

"""
Disassembly of <code object in_set at 0x107c06410, file "f1.py", line 1>:
  1 RESUME 0

  2 LOAD_FAST_BORROW 0 (x)
              LOAD_CONST 1 (frozenset({'bar', 'foo', 'baz'}))
              CONTAINS_OP 0 (in)
              RETURN_VALUE
"""

def in_list(x):
    return x in ['foo', 'bar', 'baz']

"""
Disassembly of <code object in_list at 0x107c05530, file "f1.py", line 4>:
  4 RESUME 0

  5 LOAD_FAST_BORROW 0 (x)
              LOAD_CONST 1 (('foo', 'bar', 'baz'))
              CONTAINS_OP 0 (in)
              RETURN_VALUE
"""

```

---

<div class="post-metadata">

**Author:** ![blhsing](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/blhsing/32/25812_2.png) [@blhsing](https://discuss.python.org/u/blhsing)\
**Post date:** [July 21, 2026, 8:19am UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219/58 "2026-07-21T08:19:38Z")

</div>

> [@methane](#):
>
> FWIW, frozenset is used already.

Ah very cool. So that takes away some of the optimization argument from the proposal, although still if the set literal is assigned to a name first before performing the `in` operation the compiler won’t be able to make it a frozenset.

---

<div class="post-metadata">

**Author:** ![blhsing](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/blhsing/32/25812_2.png) [@blhsing](https://discuss.python.org/u/blhsing)\
**Post date:** [July 21, 2026, 9:03am UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219/60 "2026-07-21T09:03:37Z")

</div>

But with a frozenset literal it’s then foldable:

```python
def do(a, b):
    allowed = f{'foo', 'bar', 'baz'}
    if a in allowed and b in allowed:
       ...

```

which isn’t possible if the above were written with a set literal.

---

<div class="post-metadata">

**Author:** ![methane](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/methane/32/43_2.png) [@methane](https://discuss.python.org/u/methane)\
**Post date:** [July 21, 2026, 9:21am UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219/61 "2026-07-21T09:21:27Z")

</div>

Sorry, I misread. That is a correct example where frozenset literals are useful. Without literals, you would need a global variable or a hidden keyword argument hack to avoid constructing the set every time.

We might be able to use the same compiler optimization by adding a `.freeze_and_clear()` method to set and dict. The advantage of using a method instead of display is that it can also be used when you want to create a frozendict from kwargs in O(1).

```python
    allowed = {'foo', 'bar', 'baz'}.freeze_and_clear() # compiled into LOAD_CONST frozenset

```

---

<div class="post-metadata">

**Author:** ![hugovk](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hugovk/32/14505_2.png) [@hugovk](https://discuss.python.org/u/hugovk)\
**Post date:** [July 21, 2026, 2:03pm UTC](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219/62 "2026-07-21T14:03:05Z")

</div>

A downside of the double parentheses in `frozenset((...))` is formatters such as Black and Ruff expand to add an extra level of indentation:

```python
class _User(pydantic.BaseModel):
    __dmr_force_list__ : ClassVar[frozenset[str]] = frozenset(('tags',))
    __dmr_cast_null__ : ClassVar[frozenset[str]] = frozenset(
        (
            'promo_id',
            'tags',
        )
    )

```

[Previous page](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219.md?page=2)

[Next page](https://discuss.python.org/t/pep-841-adding-frozen-syntax-to-make-immutable-types-optimizable/108219.md?page=4)
