Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do type annotations in Python enforce static type checking?

I'm trying to enforce some static type checking in a project written in Python, using typing module.

When I define a function like the one from the doc

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

and try to do something like greeting(3), I indeed got the following error

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in greeting
TypeError: must be str, not int

But when I again define a function called test

def test(a: int) -> None:
    print(a)

and do test("a"), I have a printed without any errors raised. I also tried

def test(a: str) -> None:
    print(a)

and do test(3), but no TypeError is raised.

I defined both functions in exactly the same environment, i.e. an interaction python session using iTerm. Why would this happen?


1 Answers

Type annotations in python DO NOT enforce static type checking.

Python's still a dynamic language, where the interpreter checks whether it has a method to do the operation, add a str ("hello") and add an integer (3), when it reaches this line during the execution loop. Pep-484 states the core-developers don't want to change this with annotations.

If you look at the documentation, it is called 'type hints'. Hints are not enforcement.

Type hints are really for developers and their tools (like IDEs) to better document the expected type of a parameter. But adding this form of documentation does not place any restriction the argument. It is merely documentation. In fact, it's best to think of these annotations as documentation.

The error you are seeing happens without those annotations. E.g.

>>> "Hello" + 3
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str

It is possible to develop tools to do this if you want. The annotation on the object's

__annotations__

Why is it like this? In python, we generally don't do explicit type checks. Instead, we just try to call the method, like "add 'hello' and 3" and let there be an error. It's up to the caller of the function to provide the correct types. But this also means it's up to the writer of the function to document the parameter accurately. Type hints help describe the expected type, and make it available on the object, which is useful for other tools to then hook into. Previously, we'd write this stuff as documentation, like:

def greeting(name):
    """Greeting to name
    :param name: str, the name to greet
    Returns string"""
    return "hello" + name

Use duck typing to help you out The type error you've raised would be avoided if you used built-in string formatting or cast the incoming value to a string before calling add. For example, to avoid the error you saw, you could:

 def greeting(name: str) -> str:
    """Greeting to name
    :param name: str, the name to greet
    Returns string"""
    return "hello" + str(name)

def greeting(name: str) -> str:
    """Greeting to name
    :param name: str, the name to greet
    Returns string"""
    return "hello {}".format(name)
like image 199
Donal Avatar answered Mar 25 '26 19:03

Donal



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!