Can you annotate return type when value is instance of cls?

前端 未结 3 533
闹比i
闹比i 2020-11-29 04:55

Given a class with a helper method for initialization:

class TrivialClass:
    def __init__(self, str_arg: str):
        self.string_attribute = str_arg

            


        
相关标签:
3条回答
  • 2020-11-29 05:13

    A simple way to annotate the return type is to use a string as the annotation for the return value of the class method:

    # test.py
    class TrivialClass:
      def __init__(self, str_arg: str) -> None:
        self.string_attribute = str_arg
    
      @classmethod
      def from_int(cls, int_arg: int) -> 'TrivialClass':
        str_arg = str(int_arg)
        return cls(str_arg)
    

    This passes mypy 0.560 and no errors from python:

    $ mypy test.py --disallow-untyped-defs --disallow-untyped-calls
    $ python test.py
    
    0 讨论(0)
  • 2020-11-29 05:22

    Use a generic type to indicate that you'll be returning an instance of cls:

    from typing import Type, TypeVar
    
    T = TypeVar('T', bound='TrivialClass')
    
    class TrivialClass:
        # ...
    
        @classmethod
        def from_int(cls: Type[T], int_arg: int) -> T:
            # ...
            return cls(...)
    

    Any subclass overriding the class method but then returning an instance of a parent class (TrivialClass or a subclass that is still an ancestor) would be detected as an error, because the factory method is defined as returning an instance of the type of cls.

    The bound argument specifies that T has to be a (subclass of) TrivialClass; because the class doesn't yet exist when you define the generic, you need to use a forward reference (a string with the name).

    See the Annotating instance and class methods section of PEP 484.


    Note: The first revision of this answer advocated using a forward reference naming the class itself as the return value, but issue 1212 made it possible to use generics instead, a better solution.

    As of Python 3.8, you can avoid having to use forward references in annotations when you start your module with from __future__ import annotations, but creating a TypeVar() object at module level is not an annotation.

    0 讨论(0)
  • 2020-11-29 05:23

    From Python 3.7 you can use __future__.annotations:

    from __future__ import annotations
    
    
    class TrivialClass:
        # ...
    
        @classmethod
        def from_int(cls, int_arg: int) -> TrivialClass:
            # ...
            return cls(...)
    
    

    Edit: you can't subclass TrivialClass without overriding the classmethod, but if you don't require this then I think it's neater than a forward reference.

    0 讨论(0)
提交回复
热议问题