Search code examples
pythonpython-typingmypy

How should one do upper level method that returns self with python pep484 type checking


How can one define a function in a class such that the return type of the function is the 'current class' - and not the base class. For example:

Class Parent:
   def set_common_properties_from_string( input : str ) -> <WHAT SHOULD BE HERE>
     # Do some stuff you want to do in all classes
     return self

Class Child( Parent ):
   pass

   def from_file( filename : str ) -> 'Child'
      return Child().set_common_properties_from_string() # The return type of set_common must be Child

Or should one cast it somehow? If the return type is baseclass, then it will give an error.

I know one could just drop it to two lines and add temporary variable for holding the Child(), but i think the one liner is much nicer looking.

I use mypy for type checking.


Solution

  • You can use the newly implemented (and still experimental) generic self feature, which is a mechanism designed to help solve exactly the problem you're encountering.

    Mypy supports the "generic self" feature as of version 0.4.6 (note: the latest version of mypy as of time of writing is 0.470). Unfortunately, I don't remember off the top of my head if other PEP 484 compliant type checkers support this feature yet.

    In short, what you need to do is create a new TypeVar, explicitly annotate your self variable to have that type, and also have that TypeVar be the return value.

    So in your case, you'd need to modify your code to the following:

    from typing import TypeVar
    
    T = TypeVar('T', bound='Parent')
    
    class Parent:
        def set_common_properties(self: T, input: str) -> T:
            # Do some stuff you want to do in all classes
            return self
    
    class Child(Parent):
        def from_file(self, filename: str) -> 'Child':
            # More code here
            return Child().set_common_properties(...)
    

    Note that we need to set our TypeVar to be bounded by the Parent class -- that way, within the set_common_properties method, we'd be able to call any other methods that live within Parent.

    You can find a little more information on mypy's website and within PEP 484: