from typing import Final
def random_coin_flip() -> bool:
return True # pre-computed using a real coin
a: Final = 1 if random_coin_flip() else 0 # valid, a single assignment
b: Final[int] # the type could potentially be inferred here, but lets not say that it is mandatory to support
if random_coin_flip():
b = 1
else:
b = 0 # invalid, a secondary assignment
we can see that the semantics of a and b are identical, yet we observe different type checking behaviour
Do we even need to support module-scope Final without an initializer?
from typing import Final
A: Final
A = 1
Currently only pyright and ty allow this; mypy, zuban, pyrefly, and pycroscope reject it saying that a Final variable needs an initializer.
I know the spec explicitly allows Final instance attributes to be declared in class scope without an initializer, but that seems different and more useful.
Itās useful when importing backports or optional accelerators to have constants defined based on which actual backend for something is in use.
Iām in favor of the change, but Iām not sure the wording is as precise as it could be.
This is not the only place with typing where taking into account actual code flow would improve specified behavior. I think the proposed wording and specification change is fine for now, but thereās significantly more that could be improved in the same vein which might later result in wanting more precise language.
The same branchy-initialization case that the spec change aims to allow, effectively requires an initializer-less Final declaration; otherwise it would run afoul of āonly one Final declaration allowedā.