You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
These functions do nothing at runtime! they only help with the types.
Why not cast(int, arg)?
cast completely replaces the type and we need to write a full new type.
With type narrowing it's only necessary to limit the options of the existing type.
cast can't do Intersection (yet). explained below.
Why type_assert and not a normal assert?
assert makes it slower at runtime, and sometimes we care
assert can break things when improving types of an old code base
The downsides:
Without assert or if-else conditions at runtime, the coerced narrowing ignores the real type and is dangerous, almost like cast.
With Intersection type
Until we have Intersection type, this kind of things are problematic:
classAnimal:
defsay_my_name(self) ->None:
print("My name is Animal")
@runtime_checkableclassCanFlyProtocol(Protocol):
deffly(self) ->None: ...
classBird(Animal, CanFlyProtocol):
deffly(self) ->None:
print("Fly")
deflet_it_fly(animal: Animal): # we can't restrict the argument type to be Animal AND CanFlyProtocolanimal.say_my_name()
animal.fly() # Error: "Animal" has no attribute "fly"
Even cast can't help us, but we can narrow the type!
deflet_it_fly(animal: Animal):
assertisinstance(animal, CanFlyProtocol)
animal.say_my_name()
animal.fly()
reveal_type(animal) # Revealed type: "<subclass of "Animal" and "CanFlyProtocol">"
Type checkers can understand Intersection when we narrow the type, great!
But what if we don't want to change runtime behavior? for this we can
replace assert with the suggested type_assert or ensure_type!
deflet_it_fly(animal: Animal):
type_assertisinstance(animal, CanFlyProtocol)
animal.say_my_name()
animal.fly()
reveal_type(animal) # Revealed type: "<subclass of "Animal" and "CanFlyProtocol">"
A side note: with type_assert we probably can stop adding @runtime_checkable to Protocols, if we only added it for this kind of type-hint only issues that assert isinstance(animal, CanFlyProtocol) solved.
Performing isinstance with Protocol is very slow so this benefit is not small.
My suggestion is to add a way to coerce type narrowing without any runtime change,
by adding new
type_assert
and/orensure_type
.These functions do nothing at runtime! they only help with the types.
Why not
cast(int, arg)
?cast
completely replaces the type and we need to write a full new type.With type narrowing it's only necessary to limit the options of the existing type.
cast
is more dangerous because we ignore the previous type. with narrowing we just limit the options of the previous type.cast
can't doIntersection
(yet). explained below.Why
type_assert
and not a normalassert
?assert
makes it slower at runtime, and sometimes we careassert
can break things when improving types of an old code baseThe downsides:
assert
or if-else conditions at runtime, the coerced narrowing ignores the real type and is dangerous, almost likecast
.With Intersection type
Until we have
Intersection
type, this kind of things are problematic:Even
cast
can't help us, but we can narrow the type!Type checkers can understand
Intersection
when we narrow the type, great!But what if we don't want to change runtime behavior? for this we can
replace
assert
with the suggestedtype_assert
orensure_type
!ensure_type with Not
See:
How to do
not isinstance
withensure_type
? we have two options:Add a similar
ensure_not_type
Wait for the
Not[]
typeThe text was updated successfully, but these errors were encountered: