| 245 | |
| 246 | |
| 247 | class WeakSet(object): |
| 248 | def __init__(self, data=None): |
| 249 | self.data = set() |
| 250 | |
| 251 | def _remove(item, selfref=ref(self)): |
| 252 | self = selfref() |
| 253 | if self is not None: |
| 254 | if self._iterating: |
| 255 | self._pending_removals.append(item) |
| 256 | else: |
| 257 | self.data.discard(item) |
| 258 | |
| 259 | self._remove = _remove |
| 260 | # A list of keys to be removed |
| 261 | self._pending_removals = [] |
| 262 | self._iterating = set() |
| 263 | if data is not None: |
| 264 | self.update(data) |
| 265 | |
| 266 | def _commit_removals(self): |
| 267 | l = self._pending_removals |
| 268 | discard = self.data.discard |
| 269 | while l: |
| 270 | discard(l.pop()) |
| 271 | |
| 272 | def __iter__(self): |
| 273 | with _IterationGuard(self): |
| 274 | for itemref in self.data: |
| 275 | item = itemref() |
| 276 | if item is not None: |
| 277 | yield item |
| 278 | |
| 279 | def __len__(self): |
| 280 | return sum(x() is not None for x in self.data) |
| 281 | |
| 282 | def __contains__(self, item): |
| 283 | return ref(item) in self.data |
| 284 | |
| 285 | def __reduce__(self): |
| 286 | return (self.__class__, (list(self),), |
| 287 | getattr(self, '__dict__', None)) |
| 288 | |
| 289 | __hash__ = None |
| 290 | |
| 291 | def add(self, item): |
| 292 | if self._pending_removals: |
| 293 | self._commit_removals() |
| 294 | self.data.add(ref(item, self._remove)) |
| 295 | |
| 296 | def clear(self): |
| 297 | if self._pending_removals: |
| 298 | self._commit_removals() |
| 299 | self.data.clear() |
| 300 | |
| 301 | def copy(self): |
| 302 | return self.__class__(self) |
| 303 | |
| 304 | def pop(self): |