@@ -32,201 +32,201 @@ Annotations Best Practices
3232Accessing The Annotations Dict Of An Object In Python 3.10 And Newer
3333====================================================================
3434
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.
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.
6565
6666
6767Accessing The Annotations Dict Of An Object In Python 3.9 And Older
6868===================================================================
6969
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.
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.
7474
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.
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.
8181
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::
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::
8888
89- class Base:
90- a: int = 3
91- b: str = 'abc'
89+ class Base:
90+ a: int = 3
91+ b: str = 'abc'
9292
93- class Derived(Base):
94- pass
93+ class Derived(Base):
94+ pass
9595
96- print(Derived.__annotations__)
96+ print(Derived.__annotations__)
9797
98- This will print the annotations dict from ``Base ``, not
99- ``Derived ``.
98+ This will print the annotations dict from ``Base ``, not
99+ ``Derived ``.
100100
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.
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.
108108
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::
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::
112112
113- if isinstance(o, type):
114- ann = o.__dict__.get('__annotations__', None)
115- else:
116- ann = getattr(o, '__annotations__', None)
113+ if isinstance(o, type):
114+ ann = o.__dict__.get('__annotations__', None)
115+ else:
116+ ann = getattr(o, '__annotations__', None)
117117
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.
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.
122122
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__ ``.
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__ ``.
126126
127127
128128Manually Un-Stringizing Stringized Annotations
129129==============================================
130130
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.
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.
175175
176176
177177Best Practices For ``__annotations__ `` In Any Python Version
178178============================================================
179179
180- * You should avoid assigning to the ``__annotations__ `` member
181- of objects directly. Let Python manage setting ``__annotations__ ``.
180+ * You should avoid assigning to the ``__annotations__ `` member
181+ of objects directly. Let Python manage setting ``__annotations__ ``.
182182
183- * If you do assign directly to the ``__annotations__ `` member
184- of an object, you should always set it to a ``dict `` object.
183+ * If you do assign directly to the ``__annotations__ `` member
184+ of an object, you should always set it to a ``dict `` object.
185185
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.
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.
189189
190- * You should avoid modifying ``__annotations__ `` dicts.
190+ * You should avoid modifying ``__annotations__ `` dicts.
191191
192- * You should avoid deleting the ``__annotations__ `` attribute
193- of an object.
192+ * You should avoid deleting the ``__annotations__ `` attribute
193+ of an object.
194194
195195
196196``__annotations__ `` Quirks
197197==========================
198198
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.
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.
0 commit comments