TypeGuard lets a predicate describe a narrower type to a static checker when that predicate returns true.
Python TypeGuard: a static narrowing claim is not lasting ownership
Operation contract
The predicate checks that a bounded list contains exact nonnegative integers. A successful check proves the current contents only. Another alias can append a string afterward, invalidating the runtime assumption. Copying the accepted values into an immutable tuple gives the subsequent calculation owned membership instead of relying on a mutable shared list.
Failure and ownership boundary
TypeGuard does not perform validation by itself and a checker generally trusts the predicate’s annotation. The runtime implementation must establish the declared condition. A copied tuple can still alias nested mutable objects; this fixture permits only immutable integers. Python Protocol: structural intent without runtime validation, Mypy static checks: annotations do not validate runtime payloads and Python shallow and deep copies: preserve aliases deliberately are separate concerns.
Working program
from typing import TypeGuard
def accepted_amounts(value: object) -> TypeGuard[list[int]]:
return isinstance(value, list) and len(value) <= 64 and all(type(amount) is int and 0 <= amount <= 1000000 for amount in value)
received = [125, 250]
print("accepted:", accepted_amounts(received))
owned = tuple(received) if accepted_amounts(received) else ()
alias = received
alias.append("rejected")
print("shared still accepted:", accepted_amounts(received))
print("owned total:", sum(owned))
print("boolean accepted:", accepted_amounts([True]))Output
accepted: True
shared still accepted: False
owned total: 375
boolean accepted: FalseCosts and limits
Validation and tuple construction cost O(n) work and retained references for n values. The maximum batch is 64. An annotation cannot stop another owner from changing the original list after a check.
Common Mistakes
- A narrowing predicate’s annotation is a promise its implementation must satisfy.
- A mutable alias can invalidate a previously checked condition.
Connected lessons
Python type hints: annotations do not enforce runtime arguments, Python Protocol: structural intent without runtime validation, Python shallow and deep copies: preserve aliases deliberately.
