PHP Developer News

Python Type Hints - Use object instead of Any

When starting out with Python type hints, it’s common to overuse typing.Any.
This is dangerous, since Any entirely disables type checking for a variable, allowing any operation.

If you’re using Any to mean “this object could be any type, and I don’t care what”, you probably want to use object instead.
Every object in Python inherits from object, which makes it an “opaque” type that only allows operations common to everything.
Therefore we could pass, print, or store such variables in a container, but we couldn’t do anything more specific.

Simple Example

Take these few lines of code:

from typing import Any

x: Any = 123
x.does_not_exist()We assign an int to x, which we marked explicitly as having type Any.
The next line has an operation that will fail, since ints do not have a does_not_exist() method.
But, due to the Any type, mypy does not detect the failure:

$ mypy
Success: no issues found in 1 source fileIf we didn’t care what type x contained, we would be better off typing it as object:

x: object = 123
x.does_not_exist()Mypy can then correctly detect the bug:

$ mypy error: "object" has no attribute "does_not_exist" [attr-defined]
Found 1 error in 1 file (checked 1 source file)Variable Arguments

Another example where Any can be overused is when passing through *args and **kwargs:

from typing import Any

from example import Widget

class BlueWidget(Widget):
def __init__(self, *args: Any, blueness: int = 50, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self.blueness = bluenessSince we are only passing on args and kwargs, the use of Any doesn’t really have an effect.
But if the code ever evolves to look inside args or kwargs, for example to log them, then such operations will not be type checked.

We should instead use object to declare that we don’t know or care about the types of the values in args and kwargs:

from example import Widget

class BlueWidget(Widget):
def __init__(self, *args: object, blueness: int = 50, **kwargs: object) -> None:
super().__init__(*args, **kwargs)
self.blueness = bluenessUsing object is also less work since we don’t have to import it!


Any questions?


Most Popular in Database