Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python type hint, return same type as input

Well I'm considering a case where I have a baseclass with (several) children. I have a function that takes a list of baseclass objects, and returns a new list with these objects in it.

Now if I would use a child class obviously the return is a list of those child class objects: consider the following trivial case:

from typing import Sequence, List, TypeVar


class BaseClass:
    def __init__(self, data=None, *args, **kwargs):
        super().__init__()
        self.CanCalculate = True
        if data is None:
            data = []
            self.CanCalculate = False
        self._mydata = list(data)
        self.multiplier = 1

    @property
    def data(self):
        return self._mydata


class ChildClass(BaseClass):
    def sum_mul_data(self):
        return self.multiplier * sum(self.data)


class SecondChildClass(BaseClass):
    def sum_div_data(self):
        return sum(self.data) / self.multiplier


def myFun(input: Sequence[BaseClass]) -> List[BaseClass]:
    out = []
    for n, i in enumerate(input):
        if i.CanCalculate:
            i.multiplier = 10**n
            out.append(i)
    return out


childs = [ChildClass([1,2,3,4]), ChildClass(), ChildClass([1,2,3,4])]

t = myFun(childs)
for idx in t:
    print(idx.sum_mul_data())


childs = [SecondChildClass([1,2,3,4]), SecondChildClass(), SecondChildClass([1,2,3,4])]

t = myFun(childs)
for idx in t:
    print(idx.sum_div_data())

Legal code: however pycharm (and the standard type hints) shows an error during static code analysis: "unresolved attribute reference" @ idx.sum_mul_data()

Now apparently this is due to pycharm thinking the return of the function is of type "BaseClass" - not a child. So how would I state: "return same type as input"?

I tried using a typevar: T = TypeVar("T", BaseClass), though that gave an actual error, that a single contraint can't be used in TypeVar. Interestingly using T = TypeVar("T", BaseClass, ChildClass) did work, and pycharm correctly deduced the type(hint) for sum_div_data.

like image 230
paul23 Avatar asked Sep 14 '17 14:09

paul23


People also ask

Does Python enforce type hints?

The Python runtime does not enforce function and variable type annotations. They can be used by third party tools such as type checkers, IDEs, linters, etc. This module provides runtime support for type hints. The most fundamental support consists of the types Any , Union , Callable , TypeVar , and Generic .

How does type hinting work in Python?

Introduction to Python type hints It means that you need to declare types of variables, parameters, and return values of a function upfront. The predefined types allow the compilers to check the code before compiling and running the program.

Does Python type hint throw error?

If you indicate (with type hinting) that a variable is going to store a string, but you assign it to a boolean, your code is going to run without any error, because that's how it works in Python, but the code editor is going to yell at me.

How do you type hint in Python?

Here's how you can add type hints to our function: Add a colon and a data type after each function parameter. Add an arrow ( -> ) and a data type after the function to specify the return data type.


1 Answers

You should use typevars with an upper bound: do T = TypeVar('T', bound=BaseClass) instead of T = TypeVar('T', BaseClass).

Details:

  • When you do something like T = TypeVar('T', ClassA, ClassB, ClassC...), you're creating a type variable with a value restriction. That is, you're insisting that T must be exactly one of the classes you listed.

    This is why doing T = TypeVar('T', ClassA) is disallowed: the typevar can only be equal to one class, so you might as well just use the ClassA type directly.

  • When you do something like T = TypeVar('T', bound=ClassA), you're creating a type variable with an upper bound. You're insisting that T must either be ClassA, or any of its subclasses.

like image 65
Michael0x2a Avatar answered Sep 29 '22 16:09

Michael0x2a