1

This is more or less how I would track the number of class instances, since __new__ is called every time one is made:

class MyClass():
    def __new__(klass):
        try:
            klass.__instances = klass.__instances + 1
        except NameError:
            klass.__instances = 1
        return super(MyClass,klass).__new__(klass)

Is there a magic method that is called when a new reference to a specific instance of a class is made? If not, is there a straight forward way to implement one? For example:

class MyClass():
    def __init__(self):
        self.__ref = 1
        print(self,"created.")
    def __new_reference(self):
        self.__ref = self.__ref + 1
        print("Reference to",self,"added.")
    def __del_reference(self):
        self.__ref = self.__ref - 1
        print("Reference to",self,"deleted.")

So now:

L1 = []
L2 = []
L1.append(MyClass()) #<MyClass object> created
L1[0].__ref          #1
L2.append(L1[0])     #Reference to <MyClass object> added.
L2[0].__ref          #2
L1.pop(0)            #Reference to <MyClass object> deleted.
L2[0].__ref          #1

Edit:

Here's the problem I thought I would try to solve using reference tracking.

My idea is to have an object A instance that contains multiple (weak) references to object Bs. There is a separate list containing all valid Bs. There is a list of all the As as well (thousands). The desired behavior is that when any one B is removed from the B list, for any object A to become None if it contained a reference to that particular B removed from the B list.

Community
  • 1
  • 1
Rick
  • 43,029
  • 15
  • 76
  • 119
  • The short answer is no, there is not. Objects don't get to know what references them. Why do you feel you need this? – BrenBarn Nov 21 '14 at 04:54
  • 1
    I believe this is the sort of thing that would more often be handled using the Observer pattern (Events and event handlers). http://stackoverflow.com/questions/1092531/event-system-in-python/1092617#1092617 That is, a `B` can implement a `__del__` method which notifies all the `A`s that reference it. When `A` is created it can register itself with all the `B` that is has references to. And so on for the containers that have references to an `A`. – Dunes Nov 21 '14 at 15:41
  • I am profoundly ignorant when it comes to design patterns. Time to learn! This is a wonderful suggestion thank you. – Rick Nov 21 '14 at 15:44

2 Answers2

2

As far as I know there is no magic method that does this, but maybe you could use sys.getrefcount():

Return the reference count of the object. The count returned is generally one higher than you might expect, because it includes the (temporary) reference as an argument to getrefcount().

Using your example:

>>> import sys
>>> class MyClass: pass
... 
>>> L1 = []
>>> L2 = []
>>> L1.append(MyClass())
>>> sys.getrefcount(L1[0])
2
>>> L2.append(L1[0])
>>> sys.getrefcount(L1[0])
3
>>> del L1[0]
>>> sys.getrefcount(L2[0])
2
arshajii
  • 127,459
  • 24
  • 238
  • 287
  • `sys.getrefcount` and its ilk are the nearest thing, but you'd have to constantly poll them in a loop or something in order to "monitor" new references to a particular object. – BrenBarn Nov 21 '14 at 04:53
  • sounds like i should find another approach to my problem, then. thanks! – Rick Nov 21 '14 at 13:53
0

I just thought of a simple way to almost accomplish this, and it's probably good enough for my situation.

All I have to do is be sure to call the object every time it is referenced. This isn't quite as neat and tidy as I was hoping for, but it does allow tracking of the number of references that I'm interested in (though it does not track all references).

Here's a code sample to illustrate:

class MyClass():
    def __init__(self):
        self._ref = 1
        print(self,"created.")
    def __call__(self, new_ref=True):
        if new_ref is True: self.__new_reference()
        elif new_ref is False: self.__del_reference()
        return self
    def __new_reference(self):
        self._ref = self._ref + 1
        print("Reference to",self,"added.")
    def __del_reference(self):
        self._ref = self._ref - 1
        print("Reference to",self,"deleted.")

Now I can do this:

L1 = []
L2 = []
L1.append(MyClass())   #<MyClass object> created.
print(L1[0]._ref)      #1
L2.append(L1[0](True)) #Reference to <MyClass object> added.
print(L2[0]._ref)      #2
L1.pop(0)(False)       #Reference to <MyClass object> deleted.
print(L2[0]._ref)      #1

I just have to remember to call my special object every time I add or delete it.

Alternatively, I could subclass a special container class for the special objects that calls the object with the appropriate argument when it is added or removed. Not sure if it's worth the effort to do this though.

Rick
  • 43,029
  • 15
  • 76
  • 119