1 """Thread-local objects
3 (Note that this module provides a Python version of thread
4 threading.local class. Depending on the version of Python you're
5 using, there may be a faster one available. You should always import
6 the local class from threading.)
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:
13 >>> mydata.number = 42
17 You can also access the local-object's dictionary:
21 >>> mydata.__dict__.setdefault('widgets', [])
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:
31 ... items = mydata.__dict__.items()
34 ... mydata.number = 11
35 ... log.append(mydata.number)
38 >>> thread = threading.Thread(target=f)
44 we get different data. Furthermore, changes made in the other thread
45 don't affect data seen in this thread:
50 Of course, values you get from a local object, including a __dict__
51 attribute, are for whatever thread was current at the time the
52 attribute was read. For that reason, you generally don't want to save
53 these values across threads, as they apply only to the thread they
56 You can create custom local objects by subclassing the local class:
58 >>> class MyLocal(local):
60 ... initialized = False
61 ... def __init__(self, **kw):
62 ... if self.initialized:
63 ... raise SystemError('__init__ called too many times')
64 ... self.initialized = True
65 ... self.__dict__.update(kw)
66 ... def squared(self):
67 ... return self.number ** 2
69 This can be useful to support default values, methods and
70 initialization. Note that if you define an __init__ method, it will be
71 called each time the local object is used in a separate thread. This
72 is necessary to initialize each thread's dictionary.
74 Now if we create a local object:
76 >>> mydata = MyLocal(color='red')
78 Now we have a default number:
89 And a method that operates on the data:
94 As before, we can access the data in a separate thread:
97 >>> thread = threading.Thread(target=f)
101 [[('color', 'red'), ('initialized', True)], 11]
103 without affecting this thread's data:
108 Traceback (most recent call last):
110 AttributeError: 'MyLocal' object has no attribute 'color'
112 Note that subclasses can define slots, but they are not thread
113 local. They are shared across threads:
115 >>> class MyLocal(local):
116 ... __slots__ = 'number'
118 >>> mydata = MyLocal()
119 >>> mydata.number = 42
120 >>> mydata.color = 'red'
122 So, the separate thread:
124 >>> thread = threading.Thread(target=f)
136 # Threading import is at end
138 class _localbase(object):
139 __slots__
= '_local__key', '_local__args', '_local__lock'
141 def __new__(cls
, *args
, **kw
):
142 self
= object.__new
__(cls
)
143 key
= '_local__key', 'thread.local.' + str(id(self
))
144 object.__setattr
__(self
, '_local__key', key
)
145 object.__setattr
__(self
, '_local__args', (args
, kw
))
146 object.__setattr
__(self
, '_local__lock', RLock())
148 if args
or kw
and (cls
.__init
__ is object.__init
__):
149 raise TypeError("Initialization arguments are not supported")
151 # We need to create the thread dict in anticipation of
152 # __init__ being called, to make sure we don't call it
154 dict = object.__getattribute
__(self
, '__dict__')
155 currentThread().__dict
__[key
] = dict
160 key
= object.__getattribute
__(self
, '_local__key')
161 d
= currentThread().__dict
__.get(key
)
164 currentThread().__dict
__[key
] = d
165 object.__setattr
__(self
, '__dict__', d
)
167 # we have a new instance dict, so call out __init__ if we have
170 if cls
.__init
__ is not object.__init
__:
171 args
, kw
= object.__getattribute
__(self
, '_local__args')
172 cls
.__init
__(self
, *args
, **kw
)
174 object.__setattr
__(self
, '__dict__', d
)
176 class local(_localbase
):
178 def __getattribute__(self
, name
):
179 lock
= object.__getattribute
__(self
, '_local__lock')
183 return object.__getattribute
__(self
, name
)
187 def __setattr__(self
, name
, value
):
188 lock
= object.__getattribute
__(self
, '_local__lock')
192 return object.__setattr
__(self
, name
, value
)
196 def __delattr__(self
, name
):
197 lock
= object.__getattribute
__(self
, '_local__lock')
201 return object.__delattr
__(self
, name
)
207 threading_enumerate
= enumerate
208 __getattribute__
= object.__getattribute
__
211 key
= __getattribute__(self
, '_local__key')
214 threads
= list(threading_enumerate())
216 # if enumerate fails, as it seems to do during
217 # shutdown, we'll skip cleanup under the assumption
218 # that there is nothing to clean up
221 for thread
in threads
:
223 __dict__
= thread
.__dict
__
224 except AttributeError:
225 # Thread is dying, rest in peace
232 pass # didn't have anything in this thread
238 from threading
import currentThread
, enumerate, RLock
240 from dummy_threading
import currentThread
, enumerate, RLock