This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Method __del__ with callable
Type: Stage: resolved
Components: Interpreter Core Versions: Python 3.10
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: andribas404, esoma, mark.dickinson
Priority: normal Keywords:

Created on 2021-02-24 06:44 by andribas404, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (4)
msg387609 - (view) Author: Andrey Petukhov (andribas404) Date: 2021-02-24 06:44
Is it possible to use callable to replace __del__ method of class?

if so, how to get self variable?

class A(object):
    """A."""


class C(object):
    """Callable."""
    def __call__(self, *args, **kwargs):
        print("call", args, kwargs)


def func_del(*args, **kwargs):
    """Method."""
    print("func", args, kwargs)


def del_function():
    """
    Test del.

    ('func', (<__main__.A object at 0x7f8ae5a82750>,), {})
    ('call', (), {})
    """
    c = C()
    A.__del__ = func_del
    a = A()
    del a
    A.__del__ = c
    a = A()
    del a
msg387628 - (view) Author: Erik Soma (esoma) * Date: 2021-02-24 16:16
You can wrap your callable in a regular function:
```
def hack_c():
    c = C()
    def _(*args, **kwargs):
        return c(*args, **kwargs)
    return _
A.__del__ = hack_c()
```

Or (untested) make your callable an extension type with Py_TPFLAGS_METHOD_DESCRIPTOR.


Or instead of monkey-patching __del__ make __del__ call it:

```
class A:
   my_del = lambda *args, **kwargs: None
   def __del__(self):
       self.my_del(self)
A.my_del = C()
```



This doesn't just apply to __del__, other dunders exhibit this behavior as well. It is unintuitive, but I'm pretty sure it's not a bug.
msg387632 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2021-02-24 17:25
The key difference between the func_del function and the instance C() is that func_del is a (non-data) descriptor in addition to being callable, while the instance C() is not. That makes func_del usable as a method.

If you define C as follows, you'll see the behaviour you expect:


    class C:
        def __call__(self, *args, **kwargs):
            print("call", args, kwargs)

        def __get__(self, obj, objtype=None):
              return MethodType(self, obj)

Useful reference for descriptors: https://docs.python.org/3/howto/descriptor.html

I'll close here, since this is neither a bug nor a feature request.
msg387633 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2021-02-24 17:27
Postscript: the "MethodType" that appears in the previous comment can be imported from the types module: "from types import MethodType".
History
Date User Action Args
2022-04-11 14:59:41adminsetgithub: 87476
2021-02-24 17:27:08mark.dickinsonsetmessages: + msg387633
2021-02-24 17:25:37mark.dickinsonsetstatus: open -> closed

nosy: + mark.dickinson
messages: + msg387632

resolution: not a bug
stage: resolved
2021-02-24 16:16:21esomasetnosy: + esoma
messages: + msg387628
2021-02-24 06:44:13andribas404create