> On 25 Jan 2022, at 23:50, Tony Flury <tony.fl...@btinternet.com> wrote: > > > > >> On 25/01/2022 22:28, Barry wrote: >> >>>> On 25 Jan 2022, at 14:50, Tony Flury via Python-list >>>> <python-list@python.org> wrote: >>>> >>>> >>>>> On 20/01/2022 23:12, Chris Angelico wrote: >>>>>>> On Fri, 21 Jan 2022 at 10:10, Greg Ewing <greg.ew...@canterbury.ac.nz> >>>>>>> wrote: >>>>>>> On 20/01/22 12:09 am, Chris Angelico wrote: >>>>>>> At this point, the refcount has indeed been increased. >>>>>>> >>>>>>>> return self; >>>>>>>> } >>>>>>> And then you say "my return value is this object". >>>>>>> >>>>>>> So you're incrementing the refcount, then returning it without >>>>>>> incrementing the refcount. Your code is actually equivalent to "return >>>>>>> self". >>>>>> Chris, you're not making any sense. This is C code, so there's no >>>>>> way that "return x" can change the reference count of x. >>>>> Yeah, I wasn't clear there. It was equivalent to *the Python code* >>>>> "return self". My apologies. >>>>> >>>>> > The normal thing to do is to add a reference to whatever you're >>>>> > returning. For instance, Py_RETURN_NONE will incref None and then >>>>> > return it. >>>>> > >>>>> >>>>> The OP understands that this is not a normal thing to do. He's >>>>> trying to deliberately leak a reference for the purpose of diagnosing >>>>> a problem. >>>>> >>>>> It would be interesting to see what the actual refcount is after >>>>> calling this function. >>> After calling this without a double increment in the function the ref count >>> is still only 1 - which means that the 'return self' effectively does a >>> double decrement. My original message includes the Python code which calls >>> this 'leaky' function and you can see that despite the 'leaky POC' doing an >>> increment ref count drops back to one after the return. >>> >>> You are right this is not a normal thing to do, I am trying to understand >>> the behaviour so my library does the correct thing in all cases - for >>> example - imagine you have two nodes in a tree : >>> >>> A --- > B >>> >>> And your Python code has a named reference to A, and B also maintains a >>> reference to A as it's parent. >>> >>> In this case I would expect A to have a reference count of 2 (counted as 3 >>> through sys.getrefcount() - one for the named reference in the Python code >>> - and one for the link from B back to A; I would also expect B to have a >>> reference count here of 1 (just the reference from A - assuming nothing >>> else referenced B). >>> >>> My original code was incrementing the ref counts of A and B and then >>> returning A. within the Python test code A had a refcount of 1 (and not the >>> expected 2), but the refcount from B was correct as far as I could tell. >>> >>> >>>> Yes, and that's why I was saying it would need a *second* incref. >>>> >>>> ChrisA >>> Thank you to all of you for trying to help - I accept that the only way to >>> make the code work is to do a 2nd increment. >>> >>> I don't understand why doing a 'return self' would result in a double >>> decrement - that seems utterly bizzare behaviour - it obviously works, but >>> why. >> The return self in C will not change the ref count. >> >> I would suggest setting a break point in your code and stepping out of the >> function and seeing that python’s code does to the ref count. >> >> Barry > Barry, > > something odd is going on because the Python code isn't doing anything that > would cause the reference count to go from 3 inside the C function to 1 once > the method call is complete. > > As far as I know the only things that impact the reference counts are : > > Increments due to assigning a new name or adding it to a container. > Increment due to passing the object to a function (since that binds a new > name) > Decrements due to deletion of a name > Decrement due to going out of scope > Decrement due to being removed from a container. > None of those things are happening in the python code. >
Run python and your code under a debugger and check the ref count of the object as you step through the code. Don’t just step through your code but also step through the C python code. That will allow you to see how this works at a low level. Setting a watch point on the ref count will allow you run the code and just break as the ref count changes. That is what I do when a see odd c api behaviour. Barry > As posted in the original message - immediately before the call to the C > function/method sys.getrefcount reports the count to be 2 (meaning it is > actually a 1). > > Inside the C function the ref count is incremented and the Py_REFCNT macro > reports the count as 3 inside the C function as expected (1 for the name in > the Python code, 1 for the argument as passed to the C function, and 1 for > the increment), so outside the function one would expect the ref count to now > be 2 (since the reference caused by calling the function is then reversed). > > However - Immediately outside the C function and back in the Python code > sys.getrefcount reports the count to be 2 again - meaning it is now really 1. > So that means that the refcount has been decremented twice in-between the > return of the C function and the execution of the immediate next python > statement. I understand one of those decrements - the parameter's ref count > is incremented on the way in so the same object is decremented on the way out > (so that calls don't leak references) but I don't understand where the second > decrement is coming from. > > Again there is nothing in the Python code that would cause that decrement - > the decrement behavior is in the Python runtime. > >>> >>> >>> -- >>> Anthony Flury >>> email : anthony.fl...@btinternet.com >>> >>> -- >>> https://mail.python.org/mailman/listinfo/python-list >>> > -- > Anthony Flury > email : anthony.fl...@btinternet.com -- https://mail.python.org/mailman/listinfo/python-list