[Python] How to statically enforce frozen data classes in Python?

Discussão em 'Python' iniciado por Stack, Outubro 26, 2024.

  1. Stack

    Stack Membro Participativo

    I'm trying to write an example where I'd like to use a frozen dataclass instance during type checking and swap it out with a normal dataclass to avoid paying the instantiation cost of frozen dataclasses.

    The goal is to ensure that the instance is immutable with the type checker and use a regular dataclass during runtime. Here's the snippet:

    from dataclasses import dataclass
    from typing import TYPE_CHECKING
    from functools import partial

    if TYPE_CHECKING:
    frozen = partial(dataclass, frozen=True)
    else:
    frozen = dataclass

    @frozen
    class Foo:
    x: int
    y: int

    foo = Foo(1, 2) # mypy complains about the number of arguments

    foo.x = 3 # instead, mypy should complain here


    This works as expected during runtime, but running mypy raises this error. Pyright gives me the same error as well:

    foo.py:49: error: Too many arguments for "Foo" [call-arg]


    In this snippet, the type checker can catch the mutation error:

    @dataclass(frozen=True)
    class Foo:
    x: int
    y: int

    foo = Foo(1, 2)

    foo.x = 3 # mypy correctly catches the error here


    So, I'm guessing that the type checker doesn't like when I'm aliasing frozen = dataclass or frozen = partial(...). How do I annotate this properly so that the type checker understands that it's a dataclass instance and doesn't complain about mismatched argument count?

    P.S: This is just an exercise. I know turning on dataclass(frozen=True) is way easier, and I shouldn't care about performance in such cases. I was inspired to try this after reading a blog post by Tin Tvrtković on making attr class instances frozen at compile time.

    Continue reading...

Compartilhe esta Página