So the JIT will not make any optimization for immutable types?
I didn’t get it. As far as I understood, if a frozendict is hashable, it means all its values are hashable too, like tuple. This usually[1] means all keys and values are immutable. So if hashability is a focus, why not thread safety?
this is not always true of course. See instances of custom classes for example ↩︎
That is not what the quote says. The quote says the PEP should not use performance as a motivation - independent of the PEP, performance improvements can of course be made where sensible.
I hope noone is argue for tuples because of thread saftey - this is just as incorrect of an assumption there as it is here. (For that you need something closer to PEP 795).
But again. The point is that the PEP shouldn’t exaggerate the guarantees - it may result in an incorrect perception by users that this data structure promises things it doesn’t and can’t.
Note that with maybe the exception of the last point, none of the things listed as requested by the SC are technical changes - they are all just requests to update docs to curb expectations.
I see. I took a look to the PEP, and indeed it says:
Future Work
We are also going to make frozendict to be more efficient in terms of memory usage and performance compared to dict in future.
It’s a pity if it will be a non-goal. tuple is more compact than list. Personally, when I use it explicitly, it’s mainly for this reason.
I agree that if you create a frozendict with mutable values it’s not thread safe, but if the values are (deeply) immutables too, it is.
In short, a frozendict is thread safe if it’s deeply immutable, as a tuple. In this case, it also has a hash. Maybe the PEP should mention that frozendict alone doesn’t make the map automagically immutable.
About PEP 795, I think it’s something apart. If I understood it well, it’s purpose is to avoid pickling, that would be great. But it seems to me that this PEP merely says that you can use frozendict without guards == that’s partly true, as we saw.
Coding ergonomics takes precedence in Python as the SC pointed out.
At this point I’m going to say as an admin that future discussions regarding perf are off-topic and should be a separate topic once the code lands in main.
The frozendict built-in type is now implemented in Python 3.15 (documentation). Multiple modules have already been updated to support this new type (json, pickle, pprint, etc.).
There is still an on-going work to support frozendict in more stdlib modules, and maybe also replace dict with frozendict where it is relevant. There is also an on-going work on optimizing frozendict.
You can now play with frozendict in the main branch. The future Python 3.15.0 alpha 7 release (2026-03-10) will include it.
Wouldn’t it be better to check against the Mapping protocol in that instance? Since the interfaces differ, you wouldn’t really want to handle a frozendict and a dict the same way.
They will work in that they will not match a frozendict. If they did, then they would be broken as a frozendict does not support the same methods as dict.
>>> example = frozendict(a=42)
>>> example
frozendict({'a': 42})
>>> isinstance(example, dict)
False
>>> isinstance(example, frozendict)
True
>>> match example:
... case dict():
... print("dict")
... case frozendict():
... print("frozendict")
... case _:
... print("neither")
...
frozendict
I have read the PEP and did a quick search on DPO for this, sorry if I missed something.
Has there been any discussion about having a backport for pre-3.15 releases?
I imagine something similar to what was done with backports.zstd, allowing library authors to integrate frozendict behind a guard on sys.version.
from typing import NotRequired, Required, TypedDict
class A(TypedDict, frozen=True):
a: NotRequired[int]
b: Required[int]
class B(A, frozen=True):
a: Required[int]
`B` would be a valid subtype of `A` (it would not be if they were plain `TypedDict`s). The main LSP reason (there were also PEP wording reasons) for disallowing this before was you could delete the `a` key from an `A` object, but not a `B`. Since deleting a key is disallowed for a frozen typed dict, this would no longer be an issue.
Since I used it in past, I remembered that it was “really” immutable. It seems you’re right for Python 3.11+. For previous versions, it seems it uses a C extension.