Read the signature
def double(x: float) -> float:, x: float describes the expected argument type and -> float describes the expected return type. The arrow does not return a value; the return statement in the body does that. A variable can also carry an annotation, as in exposure: float = 3.0. A collection hint such as returns: list[float] describes a list whose elements are intended to be floats.The hint does not change multiplication
Run this in ordinary Python, without a validation wrapper:
def double(x: float) -> float:
"""Return twice the supplied value."""
return x * 2
print(double(3.0))
# 6.0
print(repr(double("3")))
# '33'"3" is a string, and multiplying a string by an integer repeats it. The function therefore returns '33', despite the float return annotation. Neither annotation requests an implicit call to float().price: float to a downstream function documents its expectation; parsing and validating the incoming record still need an explicit policy.Three separate jobs
| Mechanism | What it contributes |
|---|---|
| Type annotation | States the intended type in the source. Editors and other tools can inspect it. |
| Static type checking | A separate checker compares the code's uses with its type information. With suitable checking enabled, it can report that the string call conflicts with the declared parameter type before that call runs. |
| Runtime validation | Executable guards or a validation library check actual supplied values and reject or transform them according to a chosen rule. |
A checker does not run merely because annotations are present. The example above demonstrates runtime behaviour; it is not a checker transcript.
float annotation alone does not state whether a rate is annual or monthly, whether a return is decimal or percent, or which unit of measure applies. Negative values, infinity and NaN can all be floats. State financial conventions in names and documentation, and enforce the relevant value restrictions at the data boundary.A version detail for introspection
Annotation evaluation is distinct from checking a function's arguments. In Python 3.14, annotations on functions, classes and modules are lazily evaluated by default. Code that inspects annotations should follow the version's documented introspection rules rather than assume every annotation expression runs when the function is defined. This change does not make type hints enforce runtime types. The example was executed with Python 3.14.4.
Sources
- Python 3.14: support for type hints — annotations and their non-enforcement by the runtime.
- Python 3.14 language reference: annotations and annotated assignments — syntax and evaluation semantics.
- What's new in Python 3.14: deferred annotation evaluation — the change to lazy evaluation by default.
- Python 3.14: common sequence operations — integer repetition of strings.