Polymorphism and Type Hints in Python
Asked Answered
C

2

7

Consider the following case:

class Base:
    ...

class Sub(Base):
    ...

def get_base_instance(*args) -> Base:
    ...

def do_something_with_sub(instance: Sub):
    ...

Let's say I'm calling get_base_instance in a context where I kow it will return a Sub instance - maybe based on what args I'm passing. Now I want to pass the returned instance to do_something_with_sub:

sub_instance = get_base_instance(*args)
do_something_with_sub(sub_instance)

The problem is that my IDE complains about passing a Base instance to a method that only accepts a Sub instance.

I think I remember from other programming languages that I would just cast the returned instance to Sub. How do I solve the problem in Python? Conditionally throw an exception based on the return type, or is there a better way?

Concavity answered 17/12, 2021 at 13:23 Comment(0)
F
2

I think you were on the right track when you thought about it in terms of casting. We could use cast from typing to stop the IDE complaining. For example:

from typing import cast


class Base:
    pass


class Sub(Base):
    pass


def get_base_instance(*args) -> Base:
    return Sub()


def do_something_with_sub(instance: Sub):
    print(instance)


sub_instance = cast(Sub, get_base_instance())
do_something_with_sub(sub_instance)
Forgetmenot answered 25/12, 2021 at 5:58 Comment(1)
Wow, I didn't even know this method existed, but it seems to be exactly what my intuition was looking for. Thank you!Concavity
A
0

Your IDE (probably running mypy or equivalent static type checker) is right to complain. Just like any other OOP language would complain when a function that expects a subclass is given one of its super classes. You can check the actual type dynamically with:

if isinstance(obj, Sub):
    # do something with Sub
else:
    # do something with Base
Argentum answered 17/12, 2021 at 13:32 Comment(2)
This is precisely what I wanted to avoid, and the other answer provides a way to do so. Thanks, anyway.Concavity
@TobiasFeil OK I see. You're looking for a way to do explicit casting. That's fine. You might want to make sure that your assumption about actual instance holds always. You can do so with: if isinstance(...): explicit cast here.Argentum

© 2022 - 2024 — McMap. All rights reserved.