Type cast in Python

TL;DR:
Python type cast looks like an assertion:

# Python
x = expression_returning_Base
assert isinstance(x, Derived)

This corresponds to Java or C#

// Java
Derived x = (Derived)expression_returning_Base;

In languages like Java and C++, it is a common situation when at runtime we know we have an object of type Derived, but the compiler thinks it is of type Base, so we must explicitly cast the object reference to type Derived before the compiler would allow us to use any Derived-specific properties or methods.

Python, being a dynamic type language, does not have this problem: you just call whatever methods you feel right. If such methods are not found at runtime, an exception will occur.

# Python
class Base:
  def foo(self) -> None:
    print("Base.foo()")

class Derived(Base):
  def bar(self) -> None:
    print("Derived.bar()")

def func() -> Base:
  return Derived()

x = func()
x.bar() # it works, but fails the type check

However, the situation changes in presence of type hints: x.bar() above won’t pass the type check, claiming that "Base" has no attribute "bar". This does not prevent us from running the code, but may, say, prevent from committing it to a repo if type checks are strictly enforced.

If we simply declare x of type Derived, it does not help:

x : Derived = func() # typecheck error
x.bar()

The error is Incompatible types in assignment (expression has type "Base", variable has type "Derived").

To convince the type checker that x is indeed of type Derived, we need an assertion:

x = func() 
assert isinstance(x, Derived) # type cast
x.bar()

Note, that the situation may become complicated if you apply type assertion to attributes. Unlike C++ or Java, type checking is not part of the language runtime, so whether the assert will work depends on the type checker.

x = type('test', (), {})() # empty object of custom type
x.y = func()
assert isinstance(x.y, Derived)
x.y.bar() # May or may not pass the type check

Specifically, current version of mypy recognizes this assert, but pyre does not.

2 Comments


  1. So assert is needed (only) to make type checker happy even though it does not do anything in production?

    Reply

  2. Correct. Just like type cast in Java does not do anything in production: it’s a compile time/type-checking time artifact.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *