Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How / why does Python type hinting syntax work?

I have just seen the following example in PEP 484:

def greeting(name: str) -> str:
    return 'Hello ' + name

print(greeting('Martin'))
print(greeting(1))

As expected, this does not work in Python 2:

  File "test.py", line 1
    def greeting(name: str) -> str:
                     ^
SyntaxError: invalid syntax

However, it works for Python 3:

Hello Martin
Traceback (most recent call last):
  File "test.py", line 5, in <module>
    print(greeting(1))
  File "test.py", line 2, in greeting
    return 'Hello ' + name
TypeError: Can't convert 'int' object to str implicitly

This was unexpected. It does not really check types yet, as you can see with the following example (it runs, but does not throw an exception):

def greeting(name: str) -> int:
    return 'Hello ' + name

print(greeting('Martin'))

It seems as if after the : has to be the name of a function, but the function seems to be ignored:

def aha(something):
    print("aha")
    return something+"!"

def greeting(name: aha, foo) -> int:
    return 'Hello ' + name + foo

print(greeting('Martin', 'ad'))

The same seems to be true for the name after ->.

Is this type hinting syntax using something else (like Java Modeling language makes use of comments)? When was this syntax introduced to Python? Is there a way to do static type checking already with this Syntax? Does it always break Python 2 compatibility?

like image 407
Martin Thoma Avatar asked Apr 21 '15 11:04

Martin Thoma


People also ask

Does Python enforce type hints?

Python will always remain a dynamically typed language. However, PEP 484 introduced type hints, which make it possible to also do static type checking of Python code. Unlike how types work in most other statically typed languages, type hints by themselves don't cause Python to enforce types.

How do you type hints 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.

What is the purpose of type () function in Python?

Python has a lot of built-in functions. The type() function is used to get the type of an object. When a single argument is passed to the type() function, it returns the type of the object. Its value is the same as the object.

When did Python get type hints?

With Python 3.5, type hints officially became part of the language (PEP 484).


1 Answers

There is no type hinting going on here. All you did was provide annotations; these were introduced with PEP 3107 (only in Python 3, there is no support for this in Python 2); they let you annotate arguments and return values with arbitrary information for later inspection:

>>> greeting.__annotations__
{'name': <class 'str'>, 'return': <class 'str'>}

They are otherwise not consulted at all here. Instead, the error message you got is from trying to concatenate string and integer values in the body of the function:

>>> 'Hello ' + 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't convert 'int' object to str implicitly

It is a custom type error aimed at providing additional information as to why the str + int concatenation failed; it is thrown by the str.__add__ method for any type that is not str:

>>> ''.__add__(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't convert 'int' object to str implicitly
>>> ''.__add__(True)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't convert 'bool' object to str implicitly

PEP 484 then proposes to make use of those annotations to do actual static type checking with additional tools, but as the introduction of the PEP states:

While these annotations are available at runtime through the usual __annotations__ attribute, no type checking happens at runtime. Instead, the proposal assumes the existence of a separate off-line type checker which users can run over their source code voluntarily. Essentially, such a type checker acts as a very powerful linter.

Emphasis in the original.

The PEP was inspired by existing tools that use PEP 3107 annotations; specifically the mypy project (which is looping right back by adopting PEP 484), but also the type hinting support in the PyCharm IDE and the pytypedecl project. See Guido van Rossum's original email kickstarting this effort as well as a follow-up email.

mypy apparently supports Python 2 by preprocessing the annotations, removing them before byte-compiling the source code for you, but you otherwise cannot normally use the syntax Python code meant to work in Python 2.

PEP 484 also describes the use of stub files, which sit next to the regular Python files; these use the .pyi extension and only contain the signatures (with type hints), leaving the main .py files annotation free and thus usable on Python 2 (provided you wrote Polyglot Python code otherwise).

like image 110
Martijn Pieters Avatar answered Sep 22 '22 00:09

Martijn Pieters