Python Forum
can someone explain this __del__ behaviour?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
can someone explain this __del__ behaviour?
#1
I came across something interesting that I can't explain. Perhaps someone here can. When the following code is run with the lambda commented out it produces the output I expect to see.

    class Exp:
        def __init__(self):
            print('__init__')
            self.b = 1
            #self.a = lambda: self.b

        def __del__(self):
            print('__del__')

    obj = Exp()
    obj = None
Output

    __init__
    __del__
But with the lambda uncommented

    class Exp:
        def __init__(self):
            print('__init__')
            self.b = 1
            self.a = lambda: self.b

        def __del__(self):
            print('__del__')

    obj = Exp()
    obj = None
I do not see that __del__ is executed.

    __init__
As I understand it, __del__ executes when the reference count for an object reaches zero so I can only assume that somehow the lambda line is doing something odd. But if I modify the lambda to

    class Exp:
        def __init__(self):
            print('__init__')
            self.b = 1
            self.a = lambda: 10

        def __del__(self):
            print('__del__')

    obj = Exp()
    obj = None

I get

    __init__
    __del__
I'm not a fan of lambdas, but typically a lambda specifies a parameter and something that operates on that parameter like

    self.a = lambda x: x**2


so perhaps specifying self.b in the lambda expression is causing a problem with the reference counter.
Reply
#2
A lambda expression like "lambda: self.b" creates a closure. The object self is referenced by the closure. You can see that here:
class Exp:
    def __init__(self):
        self.a = 1
        self.b = lambda: self.a

    def __str__(self):
        return f"a: {self.a}, b:{self.b()}"

obj = Exp()
print(obj)
obj.a = 2
print(obj)
a: 1, b:1
a: 2, b:2
How does the lambda expression know the value of obj.a has changed to 2? It knows because it created a closure that not only knows what code to execute (return self.a), but contains a reference to the object self. When you reassign obj = None this does not remove the reference in the lambda expression. To do that:
obj = Exp()
obj.b = None
obj = None
Now the reference count goes to zero and the object is deleted.
ibreeden likes this post
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  logger behaviour setdetnet 1 896 Apr-15-2023, 05:20 AM
Last Post: Gribouillis
  Asyncio weird behaviour vugz 2 1,262 Apr-09-2023, 01:48 AM
Last Post: vugz
  Weird behaviour using if statement in python 3.10.8 mikepy 23 3,641 Jan-18-2023, 04:51 PM
Last Post: mikepy
  Generator behaviour bla123bla 2 1,111 Jul-26-2022, 07:30 PM
Last Post: bla123bla
  Inconsistent behaviour in output - web scraping Steve 6 2,564 Sep-20-2021, 01:54 AM
Last Post: Larz60+
  Adding to the dictionary inside the for-loop - weird behaviour InputOutput007 5 2,724 Jan-21-2021, 02:21 PM
Last Post: InputOutput007
  Behaviour of 2D array SimonB 6 2,842 Jan-21-2021, 01:29 PM
Last Post: SimonB
  strange behaviour- plotting nathan_Blanc_Haifa 0 1,506 Dec-27-2020, 01:37 PM
Last Post: nathan_Blanc_Haifa
  OOP behaviour problem JohnB 3 2,435 Aug-18-2020, 07:51 PM
Last Post: JohnB
  understanding basic loop behaviour vinci 5 2,918 Feb-11-2020, 09:53 PM
Last Post: vinci

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020