upvote
> so I'm pretty sure the new preferred way is to explicitly use abstract superclasses... just like Java did all along (and is mandatory).

typing.Protocol is a good fit for this use case

  from typing import Protocol
  
  class HasMessage(Protocol):
      def get_message(self) -> str: ...
  
  class A:
      """Implicit (duck-typed)"""
      def get_message(self) -> str:
          return "A"
  
  class B(HasMessage):
      """Explicit"""
      def get_message(self) -> str:
          return "B"
  
  class C:
      def get_message(self) -> int:
          return 1
  
  def print_message(m: HasMessage) -> None:
      print(m.get_message())
  
  print_message(A())
  print_message(B())
  print_message(C())  # fails type check
reply
> Static typing in Python is the biggest hypocrisy ever

Yes, agreed. I used to work on a large python codebase and tried to add type hints where I could. The issue is that python was not the right tool for the job - except that switching to the right tool was a non-starter. So type hints were the best I could do.

reply
It is indeed a significant undertaking. But... it is doable. I've worked on a code base that converted several functionalities to golang. It did take a lot of effort and quite a lot of planning.
reply