efirvida
efirvida

Reputation: 4855

Python type hints to match different class, with common behavior

Hello everyone I'm looking for the best way to type hinting my function where I want to accept different types of class, but with common behavior. example:

class HumanPlayer:
    pass

class IAPlayer:
    pass

def play_game(player1, player2)
    pass

How can I add type hints for player1 and player2 that can support the both kinds of players? Of course I can use object or create a parent class Player. But I'm sure that this are not the right solucion.

Upvotes: 0

Views: 115

Answers (2)

deceze
deceze

Reputation: 522165

The straight forward answer would be to use typing.Union and hint against:

Union[HumanPlayer, IAPlayer]

However, this means that the passed object may have any traits of either class. As long as both classes implement the same interface, that doesn't really matter. But it's hard to keep both classes in sync just by convention, so you should think about a formal way to help that process by using a shared parent class. An ABC is very useful in this regard:

from abc import ABC, abstractmethod

class Player(ABC):
    def something_common(self):
        # do something common

    @abstractmethod
    def play(self):
        """Players must implement their specific play style."""
        raise NotImplementedError

    ...

class HumanPlayer(Player):
    def play(self):
        # play humanely

    def care_for_bodily_needs(self):
        # take a break

Now you can safely hint against Player and its well defined interface. If HumanPlayer or IAPlayer implement something the other doesn't, that won't be included in the Player interface and thus cannot safely be used inside your function play_game, making your code type safe.

def play_game(player1: Player, player2: Player):
    player1.something_common()
    player1.play()
    player2.play()

def ensure_is_comfortable(player: HumanPlayer):
    player.care_for_bodily_needs()  # only safe to call here

Upvotes: 2

yedpodtrzitko
yedpodtrzitko

Reputation: 9359

One solution would be to add a common ancestor for both classes, and use it as the type hint:

class PlayerMixin:
    pass

class HumanPlayer(PlayerMixin):
    pass

class AIPlayer(PlayerMixin):
    pass

def play_game(player1: PlayerMixin, player2: PlayerMixin)
    pass

Upvotes: 1

Related Questions