1.. _annotations-howto: 2 3************************** 4Annotations Best Practices 5************************** 6 7:author: Larry Hastings 8 9.. topic:: Abstract 10 11 This document is designed to encapsulate the best practices 12 for working with annotations dicts. If you write Python code 13 that examines ``__annotations__`` on Python objects, we 14 encourage you to follow the guidelines described below. 15 16 The document is organized into four sections: 17 best practices for accessing the annotations of an object 18 in Python versions 3.10 and newer, 19 best practices for accessing the annotations of an object 20 in Python versions 3.9 and older, 21 other best practices 22 for ``__annotations__`` that apply to any Python version, 23 and 24 quirks of ``__annotations__``. 25 26 Note that this document is specifically about working with 27 ``__annotations__``, not uses *for* annotations. 28 If you're looking for information on how to use "type hints" 29 in your code, please see the :mod:`typing` module. 30 31 32Accessing The Annotations Dict Of An Object In Python 3.10 And Newer 33==================================================================== 34 35 Python 3.10 adds a new function to the standard library: 36 :func:`inspect.get_annotations`. In Python versions 3.10 37 and newer, calling this function is the best practice for 38 accessing the annotations dict of any object that supports 39 annotations. This function can also "un-stringize" 40 stringized annotations for you. 41 42 If for some reason :func:`inspect.get_annotations` isn't 43 viable for your use case, you may access the 44 ``__annotations__`` data member manually. Best practice 45 for this changed in Python 3.10 as well: as of Python 3.10, 46 ``o.__annotations__`` is guaranteed to *always* work 47 on Python functions, classes, and modules. If you're 48 certain the object you're examining is one of these three 49 *specific* objects, you may simply use ``o.__annotations__`` 50 to get at the object's annotations dict. 51 52 However, other types of callables--for example, 53 callables created by :func:`functools.partial`--may 54 not have an ``__annotations__`` attribute defined. When 55 accessing the ``__annotations__`` of a possibly unknown 56 object, best practice in Python versions 3.10 and 57 newer is to call :func:`getattr` with three arguments, 58 for example ``getattr(o, '__annotations__', None)``. 59 60 Before Python 3.10, accessing ``__annotations__`` on a class that 61 defines no annotations but that has a parent class with 62 annotations would return the parent's ``__annotations__``. 63 In Python 3.10 and newer, the child class's annotations 64 will be an empty dict instead. 65 66 67Accessing The Annotations Dict Of An Object In Python 3.9 And Older 68=================================================================== 69 70 In Python 3.9 and older, accessing the annotations dict 71 of an object is much more complicated than in newer versions. 72 The problem is a design flaw in these older versions of Python, 73 specifically to do with class annotations. 74 75 Best practice for accessing the annotations dict of other 76 objects--functions, other callables, and modules--is the same 77 as best practice for 3.10, assuming you aren't calling 78 :func:`inspect.get_annotations`: you should use three-argument 79 :func:`getattr` to access the object's ``__annotations__`` 80 attribute. 81 82 Unfortunately, this isn't best practice for classes. The problem 83 is that, since ``__annotations__`` is optional on classes, and 84 because classes can inherit attributes from their base classes, 85 accessing the ``__annotations__`` attribute of a class may 86 inadvertently return the annotations dict of a *base class.* 87 As an example:: 88 89 class Base: 90 a: int = 3 91 b: str = 'abc' 92 93 class Derived(Base): 94 pass 95 96 print(Derived.__annotations__) 97 98 This will print the annotations dict from ``Base``, not 99 ``Derived``. 100 101 Your code will have to have a separate code path if the object 102 you're examining is a class (``isinstance(o, type)``). 103 In that case, best practice relies on an implementation detail 104 of Python 3.9 and before: if a class has annotations defined, 105 they are stored in the class's ``__dict__`` dictionary. Since 106 the class may or may not have annotations defined, best practice 107 is to call the ``get`` method on the class dict. 108 109 To put it all together, here is some sample code that safely 110 accesses the ``__annotations__`` attribute on an arbitrary 111 object in Python 3.9 and before:: 112 113 if isinstance(o, type): 114 ann = o.__dict__.get('__annotations__', None) 115 else: 116 ann = getattr(o, '__annotations__', None) 117 118 After running this code, ``ann`` should be either a 119 dictionary or ``None``. You're encouraged to double-check 120 the type of ``ann`` using :func:`isinstance` before further 121 examination. 122 123 Note that some exotic or malformed type objects may not have 124 a ``__dict__`` attribute, so for extra safety you may also wish 125 to use :func:`getattr` to access ``__dict__``. 126 127 128Manually Un-Stringizing Stringized Annotations 129============================================== 130 131 In situations where some annotations may be "stringized", 132 and you wish to evaluate those strings to produce the 133 Python values they represent, it really is best to 134 call :func:`inspect.get_annotations` to do this work 135 for you. 136 137 If you're using Python 3.9 or older, or if for some reason 138 you can't use :func:`inspect.get_annotations`, you'll need 139 to duplicate its logic. You're encouraged to examine the 140 implementation of :func:`inspect.get_annotations` in the 141 current Python version and follow a similar approach. 142 143 In a nutshell, if you wish to evaluate a stringized annotation 144 on an arbitrary object ``o``: 145 146 * If ``o`` is a module, use ``o.__dict__`` as the 147 ``globals`` when calling :func:`eval`. 148 * If ``o`` is a class, use ``sys.modules[o.__module__].__dict__`` 149 as the ``globals``, and ``dict(vars(o))`` as the ``locals``, 150 when calling :func:`eval`. 151 * If ``o`` is a wrapped callable using :func:`functools.update_wrapper`, 152 :func:`functools.wraps`, or :func:`functools.partial`, iteratively 153 unwrap it by accessing either ``o.__wrapped__`` or ``o.func`` as 154 appropriate, until you have found the root unwrapped function. 155 * If ``o`` is a callable (but not a class), use 156 ``o.__globals__`` as the globals when calling :func:`eval`. 157 158 However, not all string values used as annotations can 159 be successfully turned into Python values by :func:`eval`. 160 String values could theoretically contain any valid string, 161 and in practice there are valid use cases for type hints that 162 require annotating with string values that specifically 163 *can't* be evaluated. For example: 164 165 * :pep:`604` union types using ``|``, before support for this 166 was added to Python 3.10. 167 * Definitions that aren't needed at runtime, only imported 168 when :const:`typing.TYPE_CHECKING` is true. 169 170 If :func:`eval` attempts to evaluate such values, it will 171 fail and raise an exception. So, when designing a library 172 API that works with annotations, it's recommended to only 173 attempt to evaluate string values when explicitly requested 174 to by the caller. 175 176 177Best Practices For ``__annotations__`` In Any Python Version 178============================================================ 179 180 * You should avoid assigning to the ``__annotations__`` member 181 of objects directly. Let Python manage setting ``__annotations__``. 182 183 * If you do assign directly to the ``__annotations__`` member 184 of an object, you should always set it to a ``dict`` object. 185 186 * If you directly access the ``__annotations__`` member 187 of an object, you should ensure that it's a 188 dictionary before attempting to examine its contents. 189 190 * You should avoid modifying ``__annotations__`` dicts. 191 192 * You should avoid deleting the ``__annotations__`` attribute 193 of an object. 194 195 196``__annotations__`` Quirks 197========================== 198 199 In all versions of Python 3, function 200 objects lazy-create an annotations dict if no annotations 201 are defined on that object. You can delete the ``__annotations__`` 202 attribute using ``del fn.__annotations__``, but if you then 203 access ``fn.__annotations__`` the object will create a new empty dict 204 that it will store and return as its annotations. Deleting the 205 annotations on a function before it has lazily created its annotations 206 dict will throw an ``AttributeError``; using ``del fn.__annotations__`` 207 twice in a row is guaranteed to always throw an ``AttributeError``. 208 209 Everything in the above paragraph also applies to class and module 210 objects in Python 3.10 and newer. 211 212 In all versions of Python 3, you can set ``__annotations__`` 213 on a function object to ``None``. However, subsequently 214 accessing the annotations on that object using ``fn.__annotations__`` 215 will lazy-create an empty dictionary as per the first paragraph of 216 this section. This is *not* true of modules and classes, in any Python 217 version; those objects permit setting ``__annotations__`` to any 218 Python value, and will retain whatever value is set. 219 220 If Python stringizes your annotations for you 221 (using ``from __future__ import annotations``), and you 222 specify a string as an annotation, the string will 223 itself be quoted. In effect the annotation is quoted 224 *twice.* For example:: 225 226 from __future__ import annotations 227 def foo(a: "str"): pass 228 229 print(foo.__annotations__) 230 231 This prints ``{'a': "'str'"}``. This shouldn't really be considered 232 a "quirk"; it's mentioned here simply because it might be surprising. 233