On Thu, 3 Feb 2022 at 09:33, Barry <ba...@barrys-emacs.org> wrote: > > > > > On 2 Feb 2022, at 21:12, Marco Sulla <marco.sulla.pyt...@gmail.com> wrote: > > > > You could add a __del__ that calls stop :) > > Didn’t python3 make this non deterministic when del is called? > > I thought the recommendation is to not rely on __del__ in python3 code. >
The __del__ method is called when the object is being disposed of. Aside from some considerations about interpreter shutdown, it's perfectly reliable... as long as you understand that objects don't get disposed of when they "go out of scope", but when they run out of references and get garbage collected. So for instance, you can't depend on "x = Spam(); x = Ham()" to dispose of the Spam object instantly, because it might not get garbage collected instantly; but you can depend on __del__ getting called when the Spam object gets garbage collected. With that said, I can guarantee you that a __del__ method is NOT the right way to call stop, for one simple reason: the object will keep its own references (via the timer) so long as it is running. So it won't get garbage collected, and in fact, this is very important to it being reliable. Consider this simpler example: def call_soon(func): t = threading.Timer(10, func) t.start() When this function returns, you can no longer refer to the object 't'. Will the function be called at the appropriate time? Yes, it absolutely will, and it would be highly surprising if it didn't! So the thread itself keeps a reference to the important objects. (Side point: The OP's code is quite inefficient, as it creates a new thread for each reiteration, but there's nothing wrong with that if you're looking for something simple.) The main reason to "not rely on __del__" (and, by the way, that's nothing to do with whether it's Python 2 or Python 3, this has been true since early Py2 and possibly earlier) is that you don't know when the object will be disposed of. So if you want to guarantee that something is cleaned up, what you need is a way for the object itself to still exist, but the corresponding resource to be cleaned up. A classic example is a file object: def read_then_write(fn): with open(fn) as read_file: data = read_file.read() print(read_file) # ... transform the data as required ... with open(fn, "w") as write_file: write_file.write(data) print(write_file) After each 'with' block, the file object is still there. You can refer to it. Nothing has destroyed the object. But the file has been closed, guaranteeing that you can safely reopen it in a different mode (regardless of your OS). The same could be done with this timer; an __exit__ method would make a lot of sense here, and would allow the timer to be used in a with block to govern its execution. (It also isn't really necessary, but if you want a good Pythonic way to show the beginning and end of its use area, a 'with' block is the way to go.) ChrisA -- https://mail.python.org/mailman/listinfo/python-list