Any, object and gradual typing

typing · Essentials · 9 min

Misusing Any silently switches type checking off; knowing the alternatives keeps your hints meaningful.

Python typing is gradual: typed and untyped code mix, and Any is the bridge.

Any is compatible with every type in both directions. You can pass it anywhere and do anything with it; the checker stops checking. Unannotated parameters are implicitly Any. It's useful while migrating code or for truly dynamic values, but every Any is a hole that hides errors, and it spreads: x.foo on an Any is also Any.

object is the opposite: every value is an object, so anything can be passed in, but you may only do what all objects support (str(x), ==, hash) until you narrow it with isinstance. Use object for "accepts anything" parameters, like a logging helper.

typing.cast(T, value) tells the checker "trust me, this is T". It does nothing at runtime, so a wrong cast is a lie that won't be caught. Prefer narrowing with isinstance when possible.

# type: ignore[code] silences one error on one line; include the error code so unrelated errors on the line still show. mypy's --warn-unused-ignores finds ignores that are no longer needed.

Example

from typing import Any, cast
import json

def log_value(value: object) -> str:
    # value.upper() here -> checker error: "object" has no attribute "upper"
    if isinstance(value, str):
        return value.upper()          # fine after narrowing
    return repr(value)

raw: Any = json.loads('{"port": 8080}')
port = raw["port"] + 1                # Any: anything goes, nothing checked
config = cast(dict[str, int], raw)    # tell the checker; no runtime effect
print(log_value("hi"), log_value(42), port, config["port"])  # HI 42 8081 8080
print(cast(int, "not an int"))        # not an int  (cast never checks)

Remember

  • Any turns checking off and spreads; use it sparingly
  • object accepts anything but requires narrowing before use
  • cast() only informs the checker; it never converts or checks

Watch out for

  • Annotating parameters as Any when object (or a Protocol) would keep checking on.

Check yourself

  1. Which type lets callers pass any value but forces the function to check the type before calling methods on it?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.python.org/3/library/typing.html#the-any-type