<div dir="ltr"><div>Hello. I'm not sure if I'm posting to the right list. If it's not the</div><div>case, please tell me which one to post to.</div><div><br></div><div>Using Python 3.5.2.</div><div><br></div><div>I'm developing a C module with the help of SWIG. My library manages</div><div>objects with reference counting, much like Python, except that it's</div><div>deterministic: there's no GC.</div><div><br></div><div>I create two Python objects like this:</div><div><br></div><div> bakery = Bakery()</div><div> bread = bakery.create_bread()</div><div><br></div><div>Behind the scenes, the situation looks like this:</div><div><br></div><div> +--------------------+</div><div> | UserBread obj (Py) |</div><div> +----------^---+-----+</div><div> | :</div><div> | :</div><div> | :</div><div> +------------------+ +---------+---V---+</div><div> | Bakery obj (lib) <----------------+ Bread obj (lib) |</div><div> +--------^---+-----+ +--------^--------+</div><div> | : |</div><div> | : |</div><div> +--------+---V----+ +--------+-------+</div><div> | Bakery obj (Py) | | Bread obj (Py) |</div><div> +---------^-------+ +------^---------+</div><div> | |</div><div> | |</div><div> + +</div><div> bakery bread</div><div><br></div><div>A pipe link means one "strong" reference and a colon link means one</div><div>borrowed/weak reference.</div><div><br></div><div>I have some ownership inversion magic for the Bakery lib. and Python</div><div>objects to always coexist.</div><div><br></div><div>So here it's pretty clear what can happen. I don't know which reference</div><div>gets deleted first, but let's assume it's `bakery`. Then the situation</div><div>looks like this:</div><div><br></div><div> +--------------------+</div><div> | UserBread obj (Py) |</div><div> +----------^---+-----+</div><div> | :</div><div> | :</div><div> | :</div><div> +------------------+ +---------+---V---+</div><div> | Bakery obj (lib) <----------------+ Bread obj (lib) |</div><div> +--------^---+-----+ +--------^--------+</div><div> : | |</div><div> : | |</div><div> +--------+---V----+ +--------+-------+</div><div> | Bakery obj (Py) | | Bread obj (Py) |</div><div> +-----------------+ +------^---------+</div><div> |</div><div> |</div><div> +</div><div> bread</div><div><br></div><div>The Bakery Python object's __del__() drops the reference to its library</div><div>object, but first its reference count is incremented during this call</div><div>(so it's not really destroyed) and it's marked as only owned by the</div><div>library object from now on.</div><div><br></div><div>When `bread` gets deleted:</div><div><br></div><div>1. The Bread Python object's __del__() method gets called: the reference</div><div> to its library object is dropped.</div><div>2. The Bread library object's destroy function drops its reference to</div><div> the Bakery library object.</div><div>3. The Bakery library object's destroy function drops its reference to</div><div> the Bakery Python object.</div><div>4. The Bakery Python object's __del__() method does nothing this time,</div><div> since the object is marked as only owned by its library object</div><div> (inverted ownership).</div><div>5. The Bread library object's destroy function then drops its reference</div><div> to the UserBread Python object.</div><div><br></div><div>In the end, everything is correctly destroyed and released. This also</div><div>works if `bread` is deleted before `bakery`.</div><div><br></div><div>My problem is that this works as expected when used like this:</div><div><br></div><div> def func():</div><div> bakery = Bakery()</div><div> bread = bakery.create_bread()</div><div><br></div><div> if __name__ == '__main__':</div><div> func()</div><div><br></div><div>but NOTHING is destroyed when used like this:</div><div><br></div><div> bakery = Bakery()</div><div> bread = bakery.create_bread()</div><div><br></div><div>That is, directly during the module's initialization. It works, however,</div><div>if I delete `bread` manually:</div><div><br></div><div> bakery = Bakery()</div><div> bread = bakery.create_bread()</div><div> del bread</div><div><br></div><div>It also works with `bakery` only:</div><div><br></div><div> bakery = Bakery()</div><div><br></div><div>My question is: what could explain this?</div><div><br></div><div>My guess is that my logic is correct since it works fine in the function</div><div>call situation.</div><div><br></div><div>It feels like `bread` is never deleted in the module initialization</div><div>situation, but I don't know why: the only reference to the Bread Python</div><div>object is this `bread` name in the module... what could prevent this</div><div>object's __del__() method to be called? It works when I call `del bread`</div><div>manually: I would expect that the module finalization does the exact</div><div>same thing?</div><div><br></div><div>Am I missing anything?</div><div><br></div><div>Thanks,</div><div>Phil</div>
</div>