6

The typing module implements type hints in Python 3.5+. However, this is not enforced, it seems to currently only exist for the benefit of static type checkers such as mypy and PyCharm. I was hoping it would be a viable alternative to duck typing.

Question: Is there a way to turn on dynamic type checking in Python 3.7+ that I didn't find in Google search? So for example, if I define

def greeting(name: str) -> str:
    return name

then this should fail at execution time:

greeting([12])

I don't mind paying the time penalty for this checking, since for my purposes I would have to implement it by hand anyway with assert statements, and the type hints are far more concise and descriptive.

Update: A commenter below has noted that the typen package will enforce the type hints for me dynamically. So this is a positive answer which would update the answer of an older question which was scoped to Python 3.6 and answered in the negative. I have verified that the canonical typen example works as expected:

from typen import enforce_type_hints

@enforce_type_hints
def halve_integer(a: int) -> float:
    return a / 2

halve_integer(5)  # 2.5
halve_integer(5.0)  # ParameterTypeError

The only drawback is that every function needs to be decorated to get the behavior, rather than there being one switch to turn it on for everything.

Update 2: Answer below also notes that pydantic also solves the problem. so that's 2 positive solutions. However, pydantic seems geared more towards data modelling, and comes with some strong caveats about their validation decorator:

The validate_arguments decorator is in beta, it has been added to pydantic in v1.5 on a provisional basis. It may change significantly in future releases and its interface will not be concrete until v2. Feedback from the community while it's still provisional would be extremely useful; either comment on #1205 or create a new issue.

Lars Ericson
  • 1,952
  • 4
  • 32
  • 45
  • Im confused, duck typing is not the same as static typing. Duck typing implies if it quacks like a duck then it is a duck. Example, list and str are both iterable so in that regard they could be considered the same (if you are looking for an iterable) [though this is more coined as goose typing]. Also you can either consider using a decorator or just in your code do `if not isinstance(name, str): ....` – Error - Syntactical Remorse Aug 10 '20 at 15:51
  • You can copy this packages approach [typen](https://pypi.org/project/typen/) – Error - Syntactical Remorse Aug 10 '20 at 15:55
  • Georgy, it answers it in the negative. It is such an obvious win though to enable it in the interpreter (by say adding the same code that is somewhere in mypy), that I'm hoping someone out there has done that. That's the point of the question, so see if that someone somewhere is there. The fact that the question has been asked by someone else means that it is desirable to more than just me. It isn't feasible for me to switch to OCaml or Axiom, I want to make it work in Python. – Lars Ericson Aug 10 '20 at 16:27
  • Syntactical Remorse, I have to implement the same effect as the type hints but with dynamic checking by inserting a bunch of assert statements on the class of my function arguments. I consider this to be a form of duck typing. – Lars Ericson Aug 10 '20 at 16:29
  • Syntactical Remorse, yes, TypeN seems to be what I'm looking for. It's awkward that I have to decorate every function to get the behavior, but I don't mind doing that if it does the dynamic checking I want. Can you post this as an answer? – Lars Ericson Aug 10 '20 at 16:30

1 Answers1

3

I liked the answer that was given in this thread, so I will give it here:

You can use annotations in Python3, which might help you get some benefits of static typing.

However if static typing were to be completely enforced in Python, then it won't be Python anymore. It's a duck-typed dynamic language, and would loose all dynamism as a result. If you really intend to use a statically-typed language, you are better off not using Python.

And also quote the words from PEP 563:

Python will remain a dynamically typed language, and the authors have no desire to ever make type hints mandatory, even by convention

On a personal note, there are tools that use type annotations at runtime for type checking and validations, since annotations are accessible via __annotations__ attribute. For example, pydantic, which I use in my projects. But it has its own peculiarities, for example, it tries to do implicit type conversion when possible.

Some examples:

from pydantic import validate_arguments, ValidationError, BaseModel
... 
... 
... @validate_arguments
... def sum_foo(a: int, b: int) -> int:
...     return a + b
... 
sum_foo("Hello", 1)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "pydantic/decorator.py", line 25, in pydantic.decorator.validate_arguments.wrapper_function
  File "pydantic/decorator.py", line 107, in pydantic.decorator.ValidatedFunction.call
  File "pydantic/main.py", line 346, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for SumFoo
a
  value is not a valid integer (type=type_error.integer)
class data(BaseModel):
...     a: int = 0
...     b: int = 1
...     
d = data(a=0, b="Hello")
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "pydantic/main.py", line 346, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for data
b
  value is not a valid integer (type=type_error.integer)

alex_noname
  • 26,459
  • 5
  • 69
  • 86
  • So it's a guilty pleasure but now we know both `typen` and `pydantic` answer the question in the positive. – Lars Ericson Aug 10 '20 at 17:05
  • Perhaps in the future, they will become part of the language, but in any case, you will have a choice – alex_noname Aug 10 '20 at 17:09
  • `pydantic` seems less sure of itself than `typen` at the moment. I added their caveat in an update to the question above. I like your answer but I'm more inclined to accept `typen` as the definitive answer, if the commenter who suggested it will post as an answer. – Lars Ericson Aug 10 '20 at 17:16