Skip to content

Instantly share code, notes, and snippets.

@maxfischer2781
Created November 19, 2020 13:11
Show Gist options
  • Save maxfischer2781/67846712d566d0d0a4ff307a3fc53371 to your computer and use it in GitHub Desktop.
Save maxfischer2781/67846712d566d0d0a4ff307a3fc53371 to your computer and use it in GitHub Desktop.
Example code for SO "Type annotations for abstract classes that are coupled by a shared, arbitrary type"
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Generic, TypeVar
R = TypeVar('R', bound='Runner')
T = TypeVar('T') # result type
class Command(ABC, Generic[T, R]):
@abstractmethod
def execute(self, runner: R) -> T:
raise NotImplementedError()
# Runner is not generic in R
class Runner(ABC, Generic[T]):
# Runner.run is generic in its owner
def run(self: R, command: Command[T, R]) -> T:
return command.execute(self)
class MyRunner(Runner[bool]):
magic_level: int = 20
class MyCommand(Command[bool, MyRunner]):
def execute(self, runner: MyRunner) -> bool:
# Pseudo code to illustrate dependency on runner's attributes
return runner.magic_level > 10
if __name__ == '__main__':
command = MyCommand()
runner = MyRunner()
reveal_type(runner.run(command))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment