Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get function annotations in the 'readable' format

When inspecting at runtime the annotations of a function, one can get the class annotated for a given argument. For example:

>>> import inspect
>>> inspect.signature(f).parameters['a'].annotation
<class 'int'>

The same can be achieved by doing f.__annotations__.

However, for reasons I will spare the reader, I would like to get the annotation in readable text format. For example: a: int will be retrieved as int, not as <class 'int'>. Assume the text should be legal as input to eval.

I know I can do:

>>> str(inspect.signature(f).parameters['a'])
'a:int'

And then process this string using .split and such. But I'm wondering if there's a better way.

like image 789
Aviv Cohn Avatar asked Sep 02 '25 11:09

Aviv Cohn


2 Answers

The annotation attribute of each parameter object is a class object, so you can simply use the __name__ attribute of the class object to obtain the class name as a string:

import inspect

def f(a: int):
    pass

print(inspect.signature(f).parameters['a'].annotation.__name__)

This outputs:

int

But as @chepner pointed out, the annotation attribute can be a string if it's a forward reference, so if you want your code to be generic, you would have to take that into account. For example:

class A:
    def f(self, a: 'A'):
        pass

annotation = inspect.signature(A.f).parameters['a'].annotation
print(annotation.__name__ if isinstance(annotation, type) else annotation)

This outputs:

A
like image 164
blhsing Avatar answered Sep 03 '25 23:09

blhsing


Use the annotations feature from the __future__ module.

>>> from __future__ import annotations
>>> def f(x:int): pass
...
>>> f.__annotations__
{'x': 'int'}

This, however, was not introduced until Python 3.7. See PEP-563 for more information.

like image 42
chepner Avatar answered Sep 03 '25 23:09

chepner