Sometimes your code is too dynamic for mypy to understand. In these cases, you can use the Any type to enable dynamic typing on a fine-grained basis.
The Any type
Mypy will let you do basically anything with a value of type Any:
from typing import Any
num = 1 # Statically typed (inferred to be int)
num = 'x' # error: Incompatible types in assignment
dyn: Any = 1 # Dynamically typed (type Any)
dyn = 'x' # OK - Any accepts anything
num = dyn # No error - you can assign Any to anything
num += 1 # Oops, mypy still thinks num is an int
Think of Any as a way to locally disable type checking.
Operations on Any values
You can do anything with an Any value:
def f ( x : Any) -> int :
# All of these are valid!
x.foobar( 1 , y = 2 )
print (x[ 3 ] + 'f' )
if x:
x.z = x( 2 )
open (x).read()
return x
Values derived from Any also have type Any:
def f ( x : Any) -> None :
y = x.foo()
reveal_type(y) # Revealed type is "Any"
z = y.bar( "mypy will let you do anything to y" )
reveal_type(z) # Revealed type is "Any"
Any types may propagate through your program, making type checking less effective.
Sources of Any
Untyped function parameters
Function parameters without annotations are implicitly Any:
def f ( x ) -> None :
reveal_type(x) # Revealed type is "Any"
x.can.do[ "anything" , x]( "wants" , 2 )
Use --disallow-untyped-defs to catch this:
mypy --disallow-untyped-defs myproject
Generic types without parameters
Generic types missing type parameters treat them as Any:
from typing import List
def process ( items : List) -> None : # List[Any]
reveal_type(items) # list[Any]
Missing imports
Modules that can’t be found are treated as Any:
import some_missing_module # Type is Any
result = some_missing_module.func() # result is Any
Unannotated functions
Functions without return type annotations may return Any:
def get_value (): # Returns Any
return complex_computation()
value = get_value() # value is Any
When to use Any
Highly dynamic code
For code that’s inherently dynamic:
def load_plugin ( name : str ) -> Any:
"""Load a plugin dynamically - return type varies."""
module = __import__ (name)
return getattr (module, 'Plugin' )()
Gradual typing
When adding types to existing code:
def legacy_function ( data : Any) -> dict :
# Will add proper types later
return transform(data)
Working with third-party code
When third-party libraries lack type information:
from typing import Any
import untyped_library
def wrapper ( data : dict ) -> Any:
return untyped_library.process(data)
Alternatives to Any
Use Union types
Instead of Any, use Union when you know the possible types:
from typing import Union
# Bad
def process ( value : Any) -> Any:
return value
# Better
def process ( value : Union[ int , str ]) -> Union[ int , str ]:
return value
Use TypeVar for generic code
from typing import TypeVar
T = TypeVar( 'T' )
def first ( items : list[T]) -> T:
return items[ 0 ]
result = first([ 1 , 2 , 3 ]) # result is int, not Any
Use Protocols for duck typing
from typing import Protocol
class Drawable ( Protocol ):
def draw ( self ) -> None : ...
def render ( obj : Drawable) -> None :
obj.draw()
Use object for unknown types
When you need a value but don’t know its type:
# Bad - too permissive
def log ( value : Any) -> None :
print (value)
# Better - need to narrow before use
def log ( value : object ) -> None :
print (value) # OK - object has __str__
# value.some_method() # Error - need to narrow first
Disallowing Any
Mypy provides options to restrict Any:
Disallow untyped definitions
mypy --disallow-untyped-defs myproject
Errors on functions without complete annotations.
Disallow Any generics
mypy --disallow-any-generics myproject
Errors on generic types without type parameters:
from typing import List
items: List = [] # Error
items: List[ int ] = [] # OK
Disallow subclassing Any
mypy --disallow-subclassing-any myproject
Prevents subclassing classes with unknown types:
from some_module import BaseClass # Type is Any
class MyClass ( BaseClass ): # Error
pass
Warn on return Any
mypy --warn-return-any myproject
Warns when a function returns Any:
def get_value () -> Any: # Warning
return compute()
Dealing with Any in practice
Narrow Any values
Use type narrowing to make Any values safer:
from typing import Any, cast
def process ( data : Any) -> int :
if isinstance (data, int ):
return data # data is int here
elif isinstance (data, str ):
return int (data) # Convert str to int
else :
raise TypeError ( f "Expected int or str, got { type (data) } " )
Use cast sparingly
from typing import Any, cast
def get_value () -> Any:
return compute()
# Tell mypy you know better
value = cast( int , get_value())
print (value + 1 ) # OK
Casts are not checked at runtime - use only when you’re certain: value = cast( int , get_value()) # Might actually be str!
print (value + 1 ) # Runtime error if value is str
Document Any usage
def process_json ( data : Any) -> dict :
"""
Process JSON data.
Args:
data: JSON-decoded data (Any because JSON structure varies)
Returns:
Normalized dictionary
"""
if not isinstance (data, dict ):
raise TypeError ( "Expected dict" )
return normalize(data)
Configuration examples
Strict mode without Any
# mypy.ini
[mypy]
strict = True
# This enables:
# --disallow-any-generics
# --disallow-subclassing-any
# --disallow-untyped-defs
# --disallow-incomplete-defs
# --warn-return-any
# and more
Gradual strictness
# mypy.ini
[mypy]
warn_return_any = True
# Strict for new code
[mypy-newcode.*]
strict = True
# Relaxed for legacy code
[mypy-legacy.*]
allow_any_generics = True
Any vs object
from typing import Any
def process ( x : Any) -> None :
x.anything() # OK - no checking
x[ 0 ] # OK
x + x # OK
Use when you need maximum flexibility. def process ( x : object ) -> None :
x.anything() # Error - object has limited methods
x[ 0 ] # Error
x + x # Error
str (x) # OK - object has __str__
Use when you want some type safety.
Best practices
Minimize Any Use the most specific type possible. Prefer Union, TypeVar, or Protocol over Any.
Document reasons Add comments explaining why Any is necessary in each case.
Narrow when possible Use isinstance checks to narrow Any to specific types.
Use strict mode Enable strict mode for new code to catch Any usage early.
While Any is useful for gradual typing and dynamic code, excessive use defeats the purpose of static type checking.