@@ -24,7 +24,7 @@ See also :pep:`567` for additional details.
2424Context Variables
2525-----------------
2626
27- .. class :: ContextVar(name, [*, default])
27+ .. class :: ContextVar(name, [*, default, thread_inheritable=False ])
2828
2929 This class is used to declare a new Context Variable, e.g.::
3030
@@ -37,6 +37,71 @@ Context Variables
3737 :meth: `ContextVar.get ` when no value for the variable is found
3838 in the current context.
3939
40+ If the optional keyword-only *thread_inheritable * parameter is true,
41+ the variable's binding is inherited by new :class: `threading.Thread `
42+ instances. When :meth: `threading.Thread.start ` would otherwise start
43+ the thread with an empty context (that is, when
44+ :data: `sys.flags.thread_inherit_context ` is false and no explicit
45+ :class: `Context ` was supplied), the new thread's context is initialized
46+ with the caller's current bindings for all thread-inheritable
47+ variables. This allows individual context variables to opt in to
48+ thread inheritance on a per-variable basis.
49+
50+ These are ordinary bindings in the new thread's context: they are
51+ visible to :func: `copy_context `, may be changed independently with
52+ :meth: `ContextVar.set `, and are in turn inherited by threads started
53+ from the new thread. Threads started with an explicitly supplied
54+ context are unaffected, as are threads started by means other than
55+ :meth: `threading.Thread.start `, such as
56+ :func: `_thread.start_new_thread ` or the C API.
57+
58+ When :data: `sys.flags.thread_inherit_context ` is true, a
59+ thread-inheritable variable behaves identically to an ordinary one, so
60+ it is safe to use ``thread_inheritable=True `` unconditionally.
61+
62+ Libraries that also support Python versions without this parameter
63+ must choose how to degrade on those versions. Whether the parameter
64+ is supported can be detected by checking for the
65+ :attr: `~ContextVar.thread_inheritable ` attribute on the
66+ :class: `!ContextVar ` class. For state with a safe default in a new
67+ thread (the behavior that :class: `threading.local ` based state has
68+ always had), fall back to an ordinary context variable::
69+
70+ if hasattr(ContextVar, "thread_inheritable"):
71+ var = ContextVar("var", thread_inheritable=True)
72+ else:
73+ var = ContextVar("var")
74+
75+ With this fallback, on older versions new threads see the variable's
76+ default rather than the starting thread's binding, unless the
77+ application enables :option: `-X thread_inherit_context <-X> `.
78+
79+ For state that was previously a module-level global, reverting to the
80+ default in new threads may break existing threaded code, since such
81+ code has always seen the current global value. Those libraries can
82+ instead pick the best semantics each interpreter supports::
83+
84+ if hasattr(ContextVar, "thread_inheritable"):
85+ # Context-local and inherited by new threads.
86+ def _new_var(name, **kwargs):
87+ return ContextVar(name, thread_inheritable=True, **kwargs)
88+ elif getattr(sys.flags, "thread_inherit_context", False):
89+ # Threads inherit the whole context, so an ordinary
90+ # context variable is inherited too.
91+ _new_var = ContextVar
92+ else:
93+ # Keep the library's historical global semantics.
94+ _new_var = _GlobalVar
95+
96+ Here ``_GlobalVar `` is a class provided by the library that stores a
97+ single process-wide value. To be substitutable for
98+ :class: `ContextVar ` it must accept the same constructor arguments
99+ (*name * positional, keyword-only *default *), distinguish a missing
100+ *default * from ``default=None ``, and provide ``get() ``, ``set() ``
101+ returning a token, and ``reset() ``. This case gives up task-local
102+ isolation: concurrent tasks and threads share one value, exactly as
103+ they did before the library adopted context variables.
104+
40105 **Important: ** Context Variables should be created at the top module
41106 level and never in closures. :class: `Context ` objects hold strong
42107 references to context variables which prevents context variables
@@ -45,78 +110,22 @@ Context Variables
45110 :class: `!ContextVar `\s are :ref: `generic <generics >` over the type of
46111 their contained value.
47112
48- .. classmethod :: ContextVar.thread_inheritable(name, [*, default])
49-
50- Return a new context variable whose binding is inherited by new
51- :class: `threading.Thread ` instances. When
52- :meth: `threading.Thread.start ` would otherwise start the thread with
53- an empty context (that is, when
54- :data: `sys.flags.thread_inherit_context ` is false and no explicit
55- :class: `Context ` was supplied), the new thread's context is initialized
56- with the caller's current bindings for all thread-inheritable variables.
57- This allows individual context variables to opt in to thread inheritance
58- on a per-variable basis.
59-
60- These are ordinary bindings in the new thread's context: they are
61- visible to :func: `copy_context `, may be changed independently with
62- :meth: `ContextVar.set `, and are in turn inherited by threads started
63- from the new thread. Threads started with an explicitly supplied
64- context are unaffected, as are threads started by means other than
65- :meth: `threading.Thread.start `, such as
66- :func: `_thread.start_new_thread ` or the C API.
67-
68- The *name * and *default * parameters have the same meaning as for the
69- :class: `ContextVar ` constructor. When
70- :data: `sys.flags.thread_inherit_context ` is true, a variable created
71- with this method behaves identically to one created with
72- :class: `ContextVar `, so it is safe to use unconditionally.
73-
74- Libraries that also support Python versions without this method must
75- choose how to degrade on those versions. For state with a safe
76- default in a new thread (the behavior that :class: `threading.local `
77- based state has always had), fall back to an ordinary context
78- variable::
79-
80- _new_var = getattr(ContextVar, "thread_inheritable", ContextVar)
81- var = _new_var("var")
82-
83- With this fallback, on older versions new threads see the variable's
84- default rather than the starting thread's binding, unless the
85- application enables :option: `-X thread_inherit_context <-X> `.
86-
87- For state that was previously a module-level global, reverting to the
88- default in new threads may break existing threaded code, since such
89- code has always seen the current global value. Those libraries can
90- instead pick the best semantics each interpreter supports::
91-
92- if hasattr(ContextVar, "thread_inheritable"):
93- # Context-local and inherited by new threads.
94- _new_var = ContextVar.thread_inheritable
95- elif getattr(sys.flags, "thread_inherit_context", False):
96- # Threads inherit the whole context, so an ordinary
97- # context variable is inherited too.
98- _new_var = ContextVar
99- else:
100- # Keep the library's historical global semantics.
101- _new_var = _GlobalVar
102-
103- Here ``_GlobalVar `` is a class provided by the library that stores a
104- single process-wide value. To be substitutable for
105- :class: `ContextVar ` it must accept the same constructor arguments
106- (*name * positional, keyword-only *default *), distinguish a missing
107- *default * from ``default=None ``, and provide ``get() ``, ``set() ``
108- returning a token, and ``reset() ``. This case gives up task-local
109- isolation: concurrent tasks and threads share one value, exactly as
110- they did before the library adopted context variables.
111-
112- .. versionadded :: 3.16
113+ .. versionchanged :: 3.16
114+ Added the *thread_inheritable * parameter.
113115
114116 .. attribute :: ContextVar.name
115117
116118 The name of the variable. This is a read-only property.
117119
118120 .. versionadded :: 3.7.1
119121
122+ .. attribute :: ContextVar.thread_inheritable
123+
124+ ``True `` if the variable was created with ``thread_inheritable=True ``.
125+ This is a read-only property.
126+
127+ .. versionadded :: 3.16
128+
120129 .. method :: get([default])
121130
122131 Return a value for the context variable for the current context.
0 commit comments