0

I was reading that post about cleaning up objects, and I implemented the clever answer from @Chris. I was wondering what were the possibilities of object access at the end, to see how good I could achieve resources handling. The code is the following :

import weakref
import logging
from time import sleep


class A:
    def __init__(self):
        self.a = "We're good to go !"
        self.b = 18
        self.formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')

class B:
    def __init__(self):
        self.a = A()
        self.b = 56
        self._finalizer = weakref.finalize(self, self.close, self.a)

    @staticmethod
    def close(class_A):
        print(class_A.a)
        sleep(1)


    def amethod(self):
        print(self.a.b)

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self._finalizer()

b = B()
print(b.b)
b.amethod()

We should expect that output:

56
18
"We're good to go !"

as the string is printed out when B() is garbage collected. This is what happen in a command line. But using Spyder, I first get by running this :

56
18

And then, by running the code again:

"We're good to go !"
56
18

So the object isn't garbage collected until the next run. I added the sleep to be sure, thinking that it was maybe a problem of string buffered somehow and not being printed out, but it's clearly the whole block that is not executed. I need to trust Spyder on garbage collection here, is this behaviour documented, and how can I change it ? I'm using spyder 3.3.6 and python 3.8

  • I'm not an expert on Python memory management but I'm not surprised if cleanup of memory behaves slightly differently inside Spyder than outside because Spyder has things like the variable explorer, debugging capability and so on that I assume might be inspecting and opening extra references to your code's data. What is it that you are actually trying to test here and why do you 'need to trust Spyder' on it? Have you tried any other IDEs and do they behave differently? – nekomatic Jul 04 '23 at 09:00
  • I haven't tried another IDE (yet). I'm actually using python in command line to run the main code, but at some point, I'm using the IDE for debugging purposes, and I need some clean-up function to be executed at the end, to properly disconnect a physical device. I can change my behaviour (like using CLI only or test some other IDE, and I'll do it), but my question still is : why does Spyder behaves the way it does and how can I change that, if possible ? – The rag on din Jul 04 '23 at 09:49

1 Answers1

0

If I put your code in AB.py and run it at the command line I get:

> python AB.py
56
18
We're good to go!

If I open AB.py in Spyder 5.4.3 and click the run button I always get

56
18

in the console, and b remains visible in the variable explorer.

If I run AB.py from a Python REPL, using runpy:

> python
Python 3.10.11 etc etc
>>> import runpy
>>> vars = runpy.run_path('AB.py')
56
18
>>> vars['b']
<<run_path>.B object at 0x000001A5D1600FA0>
>>> exit()
We're good to go!

>

If I modify the last three lines of AB.py to:

with B() as b:
    print(b.b)
    b.amethod()

and run it in Spyder, I get

56
18
We're good to go!

As far as I can see all of this is expected behaviour. If it's important to you that B's __exit__ method always gets called when you have finished with the object in Spyder, either use it in a with block as above or invoke the method manually. This seems like the same thing you would do with an object that opened a file, for example.

nekomatic
  • 5,988
  • 1
  • 20
  • 27