17db96d56Sopenharmony_ci.. _annotations-howto: 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ci************************** 47db96d56Sopenharmony_ciAnnotations Best Practices 57db96d56Sopenharmony_ci************************** 67db96d56Sopenharmony_ci 77db96d56Sopenharmony_ci:author: Larry Hastings 87db96d56Sopenharmony_ci 97db96d56Sopenharmony_ci.. topic:: Abstract 107db96d56Sopenharmony_ci 117db96d56Sopenharmony_ci This document is designed to encapsulate the best practices 127db96d56Sopenharmony_ci for working with annotations dicts. If you write Python code 137db96d56Sopenharmony_ci that examines ``__annotations__`` on Python objects, we 147db96d56Sopenharmony_ci encourage you to follow the guidelines described below. 157db96d56Sopenharmony_ci 167db96d56Sopenharmony_ci The document is organized into four sections: 177db96d56Sopenharmony_ci best practices for accessing the annotations of an object 187db96d56Sopenharmony_ci in Python versions 3.10 and newer, 197db96d56Sopenharmony_ci best practices for accessing the annotations of an object 207db96d56Sopenharmony_ci in Python versions 3.9 and older, 217db96d56Sopenharmony_ci other best practices 227db96d56Sopenharmony_ci for ``__annotations__`` that apply to any Python version, 237db96d56Sopenharmony_ci and 247db96d56Sopenharmony_ci quirks of ``__annotations__``. 257db96d56Sopenharmony_ci 267db96d56Sopenharmony_ci Note that this document is specifically about working with 277db96d56Sopenharmony_ci ``__annotations__``, not uses *for* annotations. 287db96d56Sopenharmony_ci If you're looking for information on how to use "type hints" 297db96d56Sopenharmony_ci in your code, please see the :mod:`typing` module. 307db96d56Sopenharmony_ci 317db96d56Sopenharmony_ci 327db96d56Sopenharmony_ciAccessing The Annotations Dict Of An Object In Python 3.10 And Newer 337db96d56Sopenharmony_ci==================================================================== 347db96d56Sopenharmony_ci 357db96d56Sopenharmony_ci Python 3.10 adds a new function to the standard library: 367db96d56Sopenharmony_ci :func:`inspect.get_annotations`. In Python versions 3.10 377db96d56Sopenharmony_ci and newer, calling this function is the best practice for 387db96d56Sopenharmony_ci accessing the annotations dict of any object that supports 397db96d56Sopenharmony_ci annotations. This function can also "un-stringize" 407db96d56Sopenharmony_ci stringized annotations for you. 417db96d56Sopenharmony_ci 427db96d56Sopenharmony_ci If for some reason :func:`inspect.get_annotations` isn't 437db96d56Sopenharmony_ci viable for your use case, you may access the 447db96d56Sopenharmony_ci ``__annotations__`` data member manually. Best practice 457db96d56Sopenharmony_ci for this changed in Python 3.10 as well: as of Python 3.10, 467db96d56Sopenharmony_ci ``o.__annotations__`` is guaranteed to *always* work 477db96d56Sopenharmony_ci on Python functions, classes, and modules. If you're 487db96d56Sopenharmony_ci certain the object you're examining is one of these three 497db96d56Sopenharmony_ci *specific* objects, you may simply use ``o.__annotations__`` 507db96d56Sopenharmony_ci to get at the object's annotations dict. 517db96d56Sopenharmony_ci 527db96d56Sopenharmony_ci However, other types of callables--for example, 537db96d56Sopenharmony_ci callables created by :func:`functools.partial`--may 547db96d56Sopenharmony_ci not have an ``__annotations__`` attribute defined. When 557db96d56Sopenharmony_ci accessing the ``__annotations__`` of a possibly unknown 567db96d56Sopenharmony_ci object, best practice in Python versions 3.10 and 577db96d56Sopenharmony_ci newer is to call :func:`getattr` with three arguments, 587db96d56Sopenharmony_ci for example ``getattr(o, '__annotations__', None)``. 597db96d56Sopenharmony_ci 607db96d56Sopenharmony_ci Before Python 3.10, accessing ``__annotations__`` on a class that 617db96d56Sopenharmony_ci defines no annotations but that has a parent class with 627db96d56Sopenharmony_ci annotations would return the parent's ``__annotations__``. 637db96d56Sopenharmony_ci In Python 3.10 and newer, the child class's annotations 647db96d56Sopenharmony_ci will be an empty dict instead. 657db96d56Sopenharmony_ci 667db96d56Sopenharmony_ci 677db96d56Sopenharmony_ciAccessing The Annotations Dict Of An Object In Python 3.9 And Older 687db96d56Sopenharmony_ci=================================================================== 697db96d56Sopenharmony_ci 707db96d56Sopenharmony_ci In Python 3.9 and older, accessing the annotations dict 717db96d56Sopenharmony_ci of an object is much more complicated than in newer versions. 727db96d56Sopenharmony_ci The problem is a design flaw in these older versions of Python, 737db96d56Sopenharmony_ci specifically to do with class annotations. 747db96d56Sopenharmony_ci 757db96d56Sopenharmony_ci Best practice for accessing the annotations dict of other 767db96d56Sopenharmony_ci objects--functions, other callables, and modules--is the same 777db96d56Sopenharmony_ci as best practice for 3.10, assuming you aren't calling 787db96d56Sopenharmony_ci :func:`inspect.get_annotations`: you should use three-argument 797db96d56Sopenharmony_ci :func:`getattr` to access the object's ``__annotations__`` 807db96d56Sopenharmony_ci attribute. 817db96d56Sopenharmony_ci 827db96d56Sopenharmony_ci Unfortunately, this isn't best practice for classes. The problem 837db96d56Sopenharmony_ci is that, since ``__annotations__`` is optional on classes, and 847db96d56Sopenharmony_ci because classes can inherit attributes from their base classes, 857db96d56Sopenharmony_ci accessing the ``__annotations__`` attribute of a class may 867db96d56Sopenharmony_ci inadvertently return the annotations dict of a *base class.* 877db96d56Sopenharmony_ci As an example:: 887db96d56Sopenharmony_ci 897db96d56Sopenharmony_ci class Base: 907db96d56Sopenharmony_ci a: int = 3 917db96d56Sopenharmony_ci b: str = 'abc' 927db96d56Sopenharmony_ci 937db96d56Sopenharmony_ci class Derived(Base): 947db96d56Sopenharmony_ci pass 957db96d56Sopenharmony_ci 967db96d56Sopenharmony_ci print(Derived.__annotations__) 977db96d56Sopenharmony_ci 987db96d56Sopenharmony_ci This will print the annotations dict from ``Base``, not 997db96d56Sopenharmony_ci ``Derived``. 1007db96d56Sopenharmony_ci 1017db96d56Sopenharmony_ci Your code will have to have a separate code path if the object 1027db96d56Sopenharmony_ci you're examining is a class (``isinstance(o, type)``). 1037db96d56Sopenharmony_ci In that case, best practice relies on an implementation detail 1047db96d56Sopenharmony_ci of Python 3.9 and before: if a class has annotations defined, 1057db96d56Sopenharmony_ci they are stored in the class's ``__dict__`` dictionary. Since 1067db96d56Sopenharmony_ci the class may or may not have annotations defined, best practice 1077db96d56Sopenharmony_ci is to call the ``get`` method on the class dict. 1087db96d56Sopenharmony_ci 1097db96d56Sopenharmony_ci To put it all together, here is some sample code that safely 1107db96d56Sopenharmony_ci accesses the ``__annotations__`` attribute on an arbitrary 1117db96d56Sopenharmony_ci object in Python 3.9 and before:: 1127db96d56Sopenharmony_ci 1137db96d56Sopenharmony_ci if isinstance(o, type): 1147db96d56Sopenharmony_ci ann = o.__dict__.get('__annotations__', None) 1157db96d56Sopenharmony_ci else: 1167db96d56Sopenharmony_ci ann = getattr(o, '__annotations__', None) 1177db96d56Sopenharmony_ci 1187db96d56Sopenharmony_ci After running this code, ``ann`` should be either a 1197db96d56Sopenharmony_ci dictionary or ``None``. You're encouraged to double-check 1207db96d56Sopenharmony_ci the type of ``ann`` using :func:`isinstance` before further 1217db96d56Sopenharmony_ci examination. 1227db96d56Sopenharmony_ci 1237db96d56Sopenharmony_ci Note that some exotic or malformed type objects may not have 1247db96d56Sopenharmony_ci a ``__dict__`` attribute, so for extra safety you may also wish 1257db96d56Sopenharmony_ci to use :func:`getattr` to access ``__dict__``. 1267db96d56Sopenharmony_ci 1277db96d56Sopenharmony_ci 1287db96d56Sopenharmony_ciManually Un-Stringizing Stringized Annotations 1297db96d56Sopenharmony_ci============================================== 1307db96d56Sopenharmony_ci 1317db96d56Sopenharmony_ci In situations where some annotations may be "stringized", 1327db96d56Sopenharmony_ci and you wish to evaluate those strings to produce the 1337db96d56Sopenharmony_ci Python values they represent, it really is best to 1347db96d56Sopenharmony_ci call :func:`inspect.get_annotations` to do this work 1357db96d56Sopenharmony_ci for you. 1367db96d56Sopenharmony_ci 1377db96d56Sopenharmony_ci If you're using Python 3.9 or older, or if for some reason 1387db96d56Sopenharmony_ci you can't use :func:`inspect.get_annotations`, you'll need 1397db96d56Sopenharmony_ci to duplicate its logic. You're encouraged to examine the 1407db96d56Sopenharmony_ci implementation of :func:`inspect.get_annotations` in the 1417db96d56Sopenharmony_ci current Python version and follow a similar approach. 1427db96d56Sopenharmony_ci 1437db96d56Sopenharmony_ci In a nutshell, if you wish to evaluate a stringized annotation 1447db96d56Sopenharmony_ci on an arbitrary object ``o``: 1457db96d56Sopenharmony_ci 1467db96d56Sopenharmony_ci * If ``o`` is a module, use ``o.__dict__`` as the 1477db96d56Sopenharmony_ci ``globals`` when calling :func:`eval`. 1487db96d56Sopenharmony_ci * If ``o`` is a class, use ``sys.modules[o.__module__].__dict__`` 1497db96d56Sopenharmony_ci as the ``globals``, and ``dict(vars(o))`` as the ``locals``, 1507db96d56Sopenharmony_ci when calling :func:`eval`. 1517db96d56Sopenharmony_ci * If ``o`` is a wrapped callable using :func:`functools.update_wrapper`, 1527db96d56Sopenharmony_ci :func:`functools.wraps`, or :func:`functools.partial`, iteratively 1537db96d56Sopenharmony_ci unwrap it by accessing either ``o.__wrapped__`` or ``o.func`` as 1547db96d56Sopenharmony_ci appropriate, until you have found the root unwrapped function. 1557db96d56Sopenharmony_ci * If ``o`` is a callable (but not a class), use 1567db96d56Sopenharmony_ci ``o.__globals__`` as the globals when calling :func:`eval`. 1577db96d56Sopenharmony_ci 1587db96d56Sopenharmony_ci However, not all string values used as annotations can 1597db96d56Sopenharmony_ci be successfully turned into Python values by :func:`eval`. 1607db96d56Sopenharmony_ci String values could theoretically contain any valid string, 1617db96d56Sopenharmony_ci and in practice there are valid use cases for type hints that 1627db96d56Sopenharmony_ci require annotating with string values that specifically 1637db96d56Sopenharmony_ci *can't* be evaluated. For example: 1647db96d56Sopenharmony_ci 1657db96d56Sopenharmony_ci * :pep:`604` union types using ``|``, before support for this 1667db96d56Sopenharmony_ci was added to Python 3.10. 1677db96d56Sopenharmony_ci * Definitions that aren't needed at runtime, only imported 1687db96d56Sopenharmony_ci when :const:`typing.TYPE_CHECKING` is true. 1697db96d56Sopenharmony_ci 1707db96d56Sopenharmony_ci If :func:`eval` attempts to evaluate such values, it will 1717db96d56Sopenharmony_ci fail and raise an exception. So, when designing a library 1727db96d56Sopenharmony_ci API that works with annotations, it's recommended to only 1737db96d56Sopenharmony_ci attempt to evaluate string values when explicitly requested 1747db96d56Sopenharmony_ci to by the caller. 1757db96d56Sopenharmony_ci 1767db96d56Sopenharmony_ci 1777db96d56Sopenharmony_ciBest Practices For ``__annotations__`` In Any Python Version 1787db96d56Sopenharmony_ci============================================================ 1797db96d56Sopenharmony_ci 1807db96d56Sopenharmony_ci * You should avoid assigning to the ``__annotations__`` member 1817db96d56Sopenharmony_ci of objects directly. Let Python manage setting ``__annotations__``. 1827db96d56Sopenharmony_ci 1837db96d56Sopenharmony_ci * If you do assign directly to the ``__annotations__`` member 1847db96d56Sopenharmony_ci of an object, you should always set it to a ``dict`` object. 1857db96d56Sopenharmony_ci 1867db96d56Sopenharmony_ci * If you directly access the ``__annotations__`` member 1877db96d56Sopenharmony_ci of an object, you should ensure that it's a 1887db96d56Sopenharmony_ci dictionary before attempting to examine its contents. 1897db96d56Sopenharmony_ci 1907db96d56Sopenharmony_ci * You should avoid modifying ``__annotations__`` dicts. 1917db96d56Sopenharmony_ci 1927db96d56Sopenharmony_ci * You should avoid deleting the ``__annotations__`` attribute 1937db96d56Sopenharmony_ci of an object. 1947db96d56Sopenharmony_ci 1957db96d56Sopenharmony_ci 1967db96d56Sopenharmony_ci``__annotations__`` Quirks 1977db96d56Sopenharmony_ci========================== 1987db96d56Sopenharmony_ci 1997db96d56Sopenharmony_ci In all versions of Python 3, function 2007db96d56Sopenharmony_ci objects lazy-create an annotations dict if no annotations 2017db96d56Sopenharmony_ci are defined on that object. You can delete the ``__annotations__`` 2027db96d56Sopenharmony_ci attribute using ``del fn.__annotations__``, but if you then 2037db96d56Sopenharmony_ci access ``fn.__annotations__`` the object will create a new empty dict 2047db96d56Sopenharmony_ci that it will store and return as its annotations. Deleting the 2057db96d56Sopenharmony_ci annotations on a function before it has lazily created its annotations 2067db96d56Sopenharmony_ci dict will throw an ``AttributeError``; using ``del fn.__annotations__`` 2077db96d56Sopenharmony_ci twice in a row is guaranteed to always throw an ``AttributeError``. 2087db96d56Sopenharmony_ci 2097db96d56Sopenharmony_ci Everything in the above paragraph also applies to class and module 2107db96d56Sopenharmony_ci objects in Python 3.10 and newer. 2117db96d56Sopenharmony_ci 2127db96d56Sopenharmony_ci In all versions of Python 3, you can set ``__annotations__`` 2137db96d56Sopenharmony_ci on a function object to ``None``. However, subsequently 2147db96d56Sopenharmony_ci accessing the annotations on that object using ``fn.__annotations__`` 2157db96d56Sopenharmony_ci will lazy-create an empty dictionary as per the first paragraph of 2167db96d56Sopenharmony_ci this section. This is *not* true of modules and classes, in any Python 2177db96d56Sopenharmony_ci version; those objects permit setting ``__annotations__`` to any 2187db96d56Sopenharmony_ci Python value, and will retain whatever value is set. 2197db96d56Sopenharmony_ci 2207db96d56Sopenharmony_ci If Python stringizes your annotations for you 2217db96d56Sopenharmony_ci (using ``from __future__ import annotations``), and you 2227db96d56Sopenharmony_ci specify a string as an annotation, the string will 2237db96d56Sopenharmony_ci itself be quoted. In effect the annotation is quoted 2247db96d56Sopenharmony_ci *twice.* For example:: 2257db96d56Sopenharmony_ci 2267db96d56Sopenharmony_ci from __future__ import annotations 2277db96d56Sopenharmony_ci def foo(a: "str"): pass 2287db96d56Sopenharmony_ci 2297db96d56Sopenharmony_ci print(foo.__annotations__) 2307db96d56Sopenharmony_ci 2317db96d56Sopenharmony_ci This prints ``{'a': "'str'"}``. This shouldn't really be considered 2327db96d56Sopenharmony_ci a "quirk"; it's mentioned here simply because it might be surprising. 233