Duck type compatibility

In Python, certain types are compatible even though they aren’t subclasses ofeach other. For example, int objects are valid whenever float objectsare expected. Mypy supports this idiom via duck type compatibility. This issupported for a small set of built-in types:

  • int is duck type compatible with float and complex.
  • float is duck type compatible with complex.
  • In Python 2, str is duck type compatible with unicode.

For example, mypy considers an int object to be valid whenever afloat object is expected. Thus code like this is nice and cleanand also behaves as expected:

  1. import math
  2.  
  3. def degrees_to_radians(degrees: float) -> float:
  4. return math.pi * degrees / 180
  5.  
  6. n = 90 # Inferred type 'int'
  7. print(degrees_to_radians(n)) # Okay!

You can also often use Protocols and structural subtyping to achieve a similar effect ina more principled and extensible fashion. Protocols don’t apply tocases like int being compatible with float, since float is nota protocol class but a regular, concrete class, and many standard libraryfunctions expect concrete instances of float (or int).

Note

Note that in Python 2 a str object with non-ASCII characters isoften not valid when a unicode string is expected. The mypy typesystem does not consider a string with non-ASCII values as aseparate type so some programs with this kind of error willsilently pass type checking. In Python 3 str and bytes areseparate, unrelated types and this kind of error is easy todetect. This a good reason for preferring Python 3 over Python 2!

See Text and AnyStr for details on how to enforce that avalue must be a unicode string in a cross-compatible way.