Type Hints/Typing were introduced at #PEP-484 and described in more detail at #PEP-483. They look very familiar to Java Collections. Nevertheless they are a types that can be extended at your own purpose.

Documentation about typings is really straight-forward. I recommend you to check it out.

To The Point

NewType

You have types in python. Within them you can create a new types by making an inheritance.

I.e. to make new type from int you would normally do:

class NewIntType(int):
    pass

But using typing you can do this:

from typing import NewType
NewIntType = NewType('NewIntType', int)
class NewIntInheritance(int):
    pass

def sumUp(a: NewIntInheritance, b: NewIntInheritance) -> NewIntInheritance:
    return a + b

print(sumUp(NewIntInheritance(1), NewIntInheritance(2)))

from typing import NewType

NewIntTyping = NewType('NewIntTyping', int)

def sumUpTyping(a: NewIntTyping, b: NewIntTyping) -> NewIntTyping:
    return a + b

print(sumUpTyping(NewIntTyping(1), NewIntTyping(2)))

They will basically do the same. There is a difference. When you create a new type with inheritance, that you can use isinstance with it.

This code shows the difference:

NewIntTyping = NewType('NewIntTyping', int)
def checkDifferenceInheritance(a: NewIntInheritance):
    print(isinstance(a, NewIntInheritance))

def checkDifferenceTyping(a: NewIntTyping):
    print(isinstance(a, NewIntTyping))

checkDifferenceInheritance(NewIntInheritance(1))
checkDifferenceTyping(NewIntTyping(1))

It will output with this:

True
Traceback (most recent call last):
    File "test1.py", line 38, in <module>
        checkDifferenceTyping(NewIntTyping(1))
    File "test1.py", line 35, in checkDifferenceTyping
        print(isinstance(a, NewIntTyping))
TypeError: isinstance() arg 2 must be a type or tuple of types

So using typing - you should avoid isinstance or even issubclass - as mentioned in TypeVar section

Type Aliasing

There is also aliasing of types within typing. You can create aliases from other types as documentation at type aliases says:

from typing import List

ListOfFloats = List[float]
print ListOfFloats([1.0, 2.0])

Where is this usefull ? Let's say you want to annotate your function to return List of numeric type of data.

You can do that with:

from typing import TypeVar
from typing import List
T = TypeVar('T', int, float)

def sort_list(elements) -> List[T]:
    return sorted(elements)

print([1,2,20, 5, 4, 8, 3])
print(sort_list([1,2,20, 5, 4, 8, 3]))

Adding to this decorator that we have introduced at this article :

def decorator_annotation_parameters(function_wrapped):
    def wrapper(*args, **kwargs):
        annotations = function_wrapped.__annotations__
        output = function_wrapped(*args, **kwargs)
        returned_type = annotations.get('return')
        for kwarg in kwargs:
            kwarg_type = annotations.get(kwarg)
            assert type(kwargs[kwarg]) == kwarg_type
        if returned_type:
            assert type(output) == returned_type

        return output
    return wrapper

We can create a checker that will check if the output value consists of Float-Lists and matches annotation output type.

Acknowledgements

Auto-promotion

Related links

Thanks!

That's it :) Comment, share or don't - up to you.

Any suggestions what I should blog about? Poke me at Twitter: @anselmos88.

See you in the next episode! Cheers!



Comments

comments powered by Disqus