Class for finalization of weakrefable objects finalize(obj, func, *args, **kwargs) returns a callable finalizer object which will be called when obj is garbage collected. The first time the finalizer is called it evaluates func(*arg, **kwargs) and returns the result. After this
| 538 | |
| 539 | |
| 540 | class finalize: |
| 541 | """Class for finalization of weakrefable objects |
| 542 | |
| 543 | finalize(obj, func, *args, **kwargs) returns a callable finalizer |
| 544 | object which will be called when obj is garbage collected. The |
| 545 | first time the finalizer is called it evaluates func(*arg, **kwargs) |
| 546 | and returns the result. After this the finalizer is dead, and |
| 547 | calling it just returns None. |
| 548 | |
| 549 | When the program exits any remaining finalizers for which the |
| 550 | atexit attribute is true will be run in reverse order of creation. |
| 551 | By default atexit is true. |
| 552 | """ |
| 553 | |
| 554 | # Finalizer objects don't have any state of their own. They are |
| 555 | # just used as keys to lookup _Info objects in the registry. This |
| 556 | # ensures that they cannot be part of a ref-cycle. |
| 557 | |
| 558 | __slots__ = () |
| 559 | _registry = {} |
| 560 | _shutdown = False |
| 561 | _index_iter = itertools.count() |
| 562 | _dirty = False |
| 563 | _registered_with_atexit = False |
| 564 | |
| 565 | class _Info: |
| 566 | __slots__ = ("weakref", "func", "args", "kwargs", "atexit", "index") |
| 567 | |
| 568 | def __init__(self, obj, func, /, *args, **kwargs): |
| 569 | if not self._registered_with_atexit: |
| 570 | # We may register the exit function more than once because |
| 571 | # of a thread race, but that is harmless |
| 572 | import atexit |
| 573 | atexit.register(self._exitfunc) |
| 574 | finalize._registered_with_atexit = True |
| 575 | info = self._Info() |
| 576 | info.weakref = ref(obj, self) |
| 577 | info.func = func |
| 578 | info.args = args |
| 579 | info.kwargs = kwargs or None |
| 580 | info.atexit = True |
| 581 | info.index = next(self._index_iter) |
| 582 | self._registry[self] = info |
| 583 | finalize._dirty = True |
| 584 | |
| 585 | def __call__(self, _=None): |
| 586 | """If alive then mark as dead and return func(*args, **kwargs); |
| 587 | otherwise return None""" |
| 588 | info = self._registry.pop(self, None) |
| 589 | if info and not self._shutdown: |
| 590 | return info.func(*info.args, **(info.kwargs or {})) |
| 591 | |
| 592 | def detach(self): |
| 593 | """If alive then mark as dead and return (obj, func, args, kwargs); |
| 594 | otherwise return None""" |
| 595 | info = self._registry.get(self) |
| 596 | obj = info and info.weakref() |
| 597 | if obj is not None and self._registry.pop(self, None): |