Reputation: 534
The Any
-type in Python is a type annotation specifying that the type a value can take on at runtime is unconstrained and cannot be determined statically. The rules for Any
states that:
x: int = 8
y: Any = x
x: Any = 8
y: int = x
The second rule can however lead to some unsound behaviour:
x: Any = 7
y: str = x
# Statically y has the type str, while in runtime it has the type int
This behaviour might make sense in some use cases. However, I'm trying to represent the type of an external blob of data (such as from a JSON-API or a pickle object). Annotating the return type as an Any
makes sense as you don't know statically what form the data will take, and then doing isinstance
checks and pattern matching to validate and extract the exact shape of the data. However, this coercion rule makes it so that the type checker will not verify that these checks are correct, but instead silently convert the Any
-types to whatever it infers, which often is not the correct behaviour at runtime.
Currently I'm defining a Union
-type of all the possible values the type might have at runtime, but this is not a sustainable solution as I find myself constantly adding more and more variants to the Union
.
Is there any Any
-like type in Python which has only the first coercion rule, but not the second?
Upvotes: 1
Views: 136
Reputation: 50076
The object
type is a valid base for any type but not vice versa:
x: int = 8
y: object = x
x: object = 8
y: int = x # error: Incompatible types in assignment (expression has type "object", variable has type "int")
In practice, usage of :object
should be constrained just like :Any
. However, misuse of :object
does not pass silently as object
supports only the minimum operations of all types:
x: int = 8
y: object = x
if isinstance(y, int):
reveal_type(y) # note: Revealed type is "builtins.int"
elif isinstance(y, list):
reveal_type(y) # note: Revealed type is "builtins.list[Any]"
else:
reveal_type(y) # note: Revealed type is "builtins.object"
Upvotes: 3