0

please review the following code…

class Client(MqC):                                                                                                 

  def __init__(self, tmpl=None):                                                                                   
    self.ConfigSetBgError(self.BgError)                                                                          
    MqC.__init__(self)                                                                                             

  def BgError(self):                                                                                               
    ... do some stuff……

I can add the callback BgError as class or as object callback…

  1. class = self.ConfigSetBgError(Client.BgError)
  2. object = self.ConfigSetBgError(self.BgError)

both cases are working because the callback code can handle this

the problem is the refCount of the self object… the case (2) increment the refCount by ONE… so the following code shows the difference code…

cl = Client()
print("refCount=" + str(sys.getrefcount(cl)))
cl = None
  1. .tp_dealloc is called… because refCount=2
  2. .tp_dealloc is NOT called because refCount=3

→ so… question… ho to solve this refCount cleanup issue ?

Swordfish
  • 12,971
  • 3
  • 21
  • 43
Andreas Otto
  • 311
  • 1
  • 10

1 Answers1

0

If you are worried about the callback keeping the instance alive, then don't pass in a bound method. self.BgError creates a method object (through the descriptor protocol), which references the instance object because it needs to have access to that instance when you call it; that's how the self parameter is passed in in the first place.

If you don't need to reference the instance state and the callback API can handle unbound methods or class method or static methods, then pass one of those in instead.

For example, you can make BgError a class method or static method:

@classmethod
def BgError(cls):
    # ...

Now both Client.BgError and self.BgError (instance_of_Client.BgError) produce a method object bound to the class instead of the instance, giving you consistent behaviour. No additional reference to the instance is made.

If you do need the instance state, pass in a wrapper function with a weak reference to your instance. When invoked, check if the weak reference is still available before using the instance. Also see using python WeakSet to enable a callback functionality for a more in-depth post about callbacks and weak references. There the callback registry takes care of producing and storing weak references, but the same principles apply.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343