44 class. Depending on the version of Python you're using, there may be a
55 faster one available. You should always import the `local` class from
66 `threading`.)
7-
8- Thread-local objects support the management of thread-local data.
9- If you have data that you want to be local to a thread, simply create
10- a thread-local object and use its attributes:
11-
12- >>> mydata = local()
13- >>> mydata.number = 42
14- >>> mydata.number
15- 42
16-
17- You can also access the local-object's dictionary:
18-
19- >>> mydata.__dict__
20- {'number': 42}
21- >>> mydata.__dict__.setdefault('widgets', [])
22- []
23- >>> mydata.widgets
24- []
25-
26- What's important about thread-local objects is that their data are
27- local to a thread. If we access the data in a different thread:
28-
29- >>> log = []
30- >>> def f():
31- ... items = sorted(mydata.__dict__.items())
32- ... log.append(items)
33- ... mydata.number = 11
34- ... log.append(mydata.number)
35-
36- >>> import threading
37- >>> thread = threading.Thread(target=f)
38- >>> thread.start()
39- >>> thread.join()
40- >>> log
41- [[], 11]
42-
43- we get different data. Furthermore, changes made in the other thread
44- don't affect data seen in this thread:
45-
46- >>> mydata.number
47- 42
48-
49- Of course, values you get from a local object, including a __dict__
50- attribute, are for whatever thread was current at the time the
51- attribute was read. For that reason, you generally don't want to save
52- these values across threads, as they apply only to the thread they
53- came from.
54-
55- You can create custom local objects by subclassing the local class:
56-
57- >>> class MyLocal(local):
58- ... number = 2
59- ... initialized = False
60- ... def __init__(self, **kw):
61- ... if self.initialized:
62- ... raise SystemError('__init__ called too many times')
63- ... self.initialized = True
64- ... self.__dict__.update(kw)
65- ... def squared(self):
66- ... return self.number ** 2
67-
68- This can be useful to support default values, methods and
69- initialization. Note that if you define an __init__ method, it will be
70- called each time the local object is used in a separate thread. This
71- is necessary to initialize each thread's dictionary.
72-
73- Now if we create a local object:
74-
75- >>> mydata = MyLocal(color='red')
76-
77- Now we have a default number:
78-
79- >>> mydata.number
80- 2
81-
82- an initial color:
83-
84- >>> mydata.color
85- 'red'
86- >>> del mydata.color
87-
88- And a method that operates on the data:
89-
90- >>> mydata.squared()
91- 4
92-
93- As before, we can access the data in a separate thread:
94-
95- >>> log = []
96- >>> thread = threading.Thread(target=f)
97- >>> thread.start()
98- >>> thread.join()
99- >>> log
100- [[('color', 'red'), ('initialized', True)], 11]
101-
102- without affecting this thread's data:
103-
104- >>> mydata.number
105- 2
106- >>> mydata.color
107- Traceback (most recent call last):
108- ...
109- AttributeError: 'MyLocal' object has no attribute 'color'
110-
111- Note that subclasses can define slots, but they are not thread
112- local. They are shared across threads:
113-
114- >>> class MyLocal(local):
115- ... __slots__ = 'number'
116-
117- >>> mydata = MyLocal()
118- >>> mydata.number = 42
119- >>> mydata.color = 'red'
120-
121- So, the separate thread:
122-
123- >>> thread = threading.Thread(target=f)
124- >>> thread.start()
125- >>> thread.join()
126-
127- affects what we see:
128-
129- >>> # TODO: RUSTPYTHON, __slots__
130- >>> mydata.number #doctest: +SKIP
131- 11
132-
133- >>> del mydata
1347"""
1358
1369from weakref import ref
@@ -194,7 +67,6 @@ def thread_deleted(_, idt=idt):
19467
19568@contextmanager
19669def _patch (self ):
197- old = object .__getattribute__ (self , '__dict__' )
19870 impl = object .__getattribute__ (self , '_local__impl' )
19971 try :
20072 dct = impl .get_dict ()
@@ -205,13 +77,12 @@ def _patch(self):
20577 with impl .locallock :
20678 object .__setattr__ (self , '__dict__' , dct )
20779 yield
208- object .__setattr__ (self , '__dict__' , old )
20980
21081
21182class local :
21283 __slots__ = '_local__impl' , '__dict__'
21384
214- def __new__ (cls , * args , ** kw ):
85+ def __new__ (cls , / , * args , ** kw ):
21586 if (args or kw ) and (cls .__init__ is object .__init__ ):
21687 raise TypeError ("Initialization arguments are not supported" )
21788 self = object .__new__ (cls )
0 commit comments