@@ -260,23 +260,133 @@ All of the methods described below are executed atomically.
260260Thread-Local Data
261261-----------------
262262
263- Thread-local data is data whose values are thread specific. To manage
264- thread-local data, just create an instance of :class: ` local ` (or a
265- subclass) and store attributes on it ::
263+ Thread-local data is data whose values are thread specific. If you
264+ have data that you want to be local to a thread, simply create a
265+ :class: ` local ` object and use its attributes ::
266266
267- mydata = threading.local()
268- mydata.x = 1
267+ >>> mydata = local()
268+ >>> mydata.number = 42
269+ >>> mydata.number
270+ 42
269271
270- The instance's values will be different for separate threads.
272+ You can also access the :class: `local `-object's dictionary::
273+
274+ >>> mydata.__dict__
275+ {'number': 42}
276+ >>> mydata.__dict__.setdefault('widgets', [])
277+ []
278+ >>> mydata.widgets
279+ []
280+
281+ What's important about thread-local objects is that their data are
282+ local to a thread. If we access the data in a different thread::
283+
284+ >>> log = []
285+ >>> def f():
286+ ... items = sorted(mydata.__dict__.items())
287+ ... log.append(items)
288+ ... mydata.number = 11
289+ ... log.append(mydata.number)
290+
291+ >>> import threading
292+ >>> thread = threading.Thread(target=f)
293+ >>> thread.start()
294+ >>> thread.join()
295+ >>> log
296+ [[], 11]
297+
298+ we get different data. Furthermore, changes made in the other thread
299+ don't affect data seen in this thread:
300+
301+ >>> mydata.number
302+ 42
303+
304+ Of course, values you get from a :class: `local ` object, including their
305+ :attr: `~object.__dict__ ` attribute, are for whatever thread was current
306+ at the time the attribute was read. For that reason, you generally
307+ don't want to save these values across threads, as they apply only to
308+ the thread they came from.
309+
310+ You can create custom :class: `local ` objects by subclassing the
311+ :class: `local ` class::
312+
313+ >>> class MyLocal(local):
314+ ... number = 2
315+ ... def __init__(self, /, **kw):
316+ ... self.__dict__.update(kw)
317+ ... def squared(self):
318+ ... return self.number ** 2
319+
320+ This can be useful to support default values, methods and
321+ initialization. Note that if you define an :py:meth: `~object.__init__ `
322+ method, it will be called each time the :class: `local ` object is used
323+ in a separate thread. This is necessary to initialize each thread's
324+ dictionary.
325+
326+ Now if we create a :class: `local ` object::
327+
328+ >>> mydata = MyLocal(color='red')
329+
330+ we have a default number::
331+
332+ >>> mydata.number
333+ 2
334+
335+ an initial color::
336+
337+ >>> mydata.color
338+ 'red'
339+ >>> del mydata.color
340+
341+ And a method that operates on the data::
342+
343+ >>> mydata.squared()
344+ 4
345+
346+ As before, we can access the data in a separate thread::
347+
348+ >>> log = []
349+ >>> thread = threading.Thread(target=f)
350+ >>> thread.start()
351+ >>> thread.join()
352+ >>> log
353+ [[('color', 'red')], 11]
354+
355+ without affecting this thread's data::
356+
357+ >>> mydata.number
358+ 2
359+ >>> mydata.color
360+ Traceback (most recent call last):
361+ ...
362+ AttributeError: 'MyLocal' object has no attribute 'color'
363+
364+ Note that subclasses can define :term: `__slots__ `, but they are not
365+ thread local. They are shared across threads::
366+
367+ >>> class MyLocal(local):
368+ ... __slots__ = 'number'
369+
370+ >>> mydata = MyLocal()
371+ >>> mydata.number = 42
372+ >>> mydata.color = 'red'
373+
374+ So, the separate thread::
375+
376+ >>> thread = threading.Thread(target=f)
377+ >>> thread.start()
378+ >>> thread.join()
379+
380+ affects what we see::
381+
382+ >>> mydata.number
383+ 11
271384
272385
273386.. class :: local()
274387
275388 A class that represents thread-local data.
276389
277- For more details and extensive examples, see the documentation string of the
278- :mod: `!_threading_local ` module: :source: `Lib/_threading_local.py `.
279-
280390
281391.. _thread-objects :
282392
0 commit comments