[Python-ideas] Type hints for functions with side-effects and for functions raising exceptions

Miikka Salminen miikka.salminen at gmail.com
Tue Feb 19 16:05:55 EST 2019


 Hi!

To help automatic document generators and static type checkers reason more
about the code, the possible side-effects and raised exceptions could also
be annotated in a standardized way.

I'll let some example code talk on my behalf. Here's a simple decorator for
annotating exceptions:
In [1]: import typing as t

In [2]: def raises(exc: Exception) -> t.Callable:
   ...:     def decorator(fn: t.Callable) -> t.Callable:
   ...:         fn.__annotations__["__raises__"] = exc
   ...:         return fn
   ...:     return decorator
   ...:

In [3]: @raises(ValueError)
   ...: def hello_if_5(x: int) -> None:
   ...:     if x != 5:
   ...:         raise ValueError("number other than 5 given")
   ...:     print("Hello!")
   ...:

In [4]: hello_if_5.__annotations__
Out[4]: {'x': int, 'return': None, '__raises__': ValueError}

In [5]: hello_if_5(1)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-5-7fb1d79ce3f4> in <module>
----> 1 hello_if_5(1)

<ipython-input-3-1084d197ce1b> in hello_if_5(x)
      2 def hello_if_5(x: int) -> None:
      3     if x != 5:
----> 4         raise ValueError("number other than 5 given")
      5     print("Hello!")
      6

ValueError: number other than 5 given

In [6]: hello_if_5(5)
Hello!

In [7]:

and here's a simple decorator for annotating side-effects:

In [1]: import typing as t

In [2]: def side_effect(has_side_effect: bool) -> t.Callable:
   ...:     def decorator(fn: t.Callable) -> t.Callable:
   ...:         fn.__annotations__["__side_effect__"] = has_side_effect
   ...:         return fn
   ...:     return decorator
   ...:

In [3]: a = 10

In [4]: @side_effect(True)
   ...: def change_a(val: int) -> None:
   ...:     global a
   ...:     a = val
   ...:

In [5]: change_a.__annotations__
Out[5]: {'val': int, 'return': None, '__side_effect__': True}

In [6]: change_a(100)

In [7]: a
Out[7]: 100

In [8]: @side_effect(True)
   ...: def mutate_list(items: t.List) -> None:
   ...:     items.append("new item")
   ...:

In [9]: mutate_list.__annotations__
Out[9]: {'items': typing.List, 'return': None, '__side_effect__': True}

In [10]: l = ["old item"]

In [11]: mutate_list(l)

In [12]: l
Out[12]: ['old item', 'new item']

In [13]:

The example implementations have some obvious limitations, such as only
allowing one error type. What do you think of the idea in general? Do you
feel this is something that could be included in Python? typing would
probably be a good module to store such decorators, I guess…

Miikka Salminen
miikka.salminen at gmail.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20190219/98a56eb5/attachment.html>


More information about the Python-ideas mailing list