Well, maybe that it's common to do in Python. However it's definitely not common in other languages and not a proper OOP way. (I don't want to start a language war - au contraire, Python is a very good language/environment for some use cases.)
There are times where you absolutely want to have track of instances of particular class. (DI containers, resources which are not managed by a garbage collector (if you have any) ...)
Usually it's solved by implementing a factory pattern. Here is quite a good article about it in Python:
http://python-3-patterns-idioms-test.readthedocs.io/en/latest/Factory.html
When a class instance is created, a reference to it can be put into a collection. There is a glitch, however (when using languages which have garbage collector or smart pointers). When somebody stops using the instance, your register still have a reference to the instance and therefore it's not garbage collected. You have to use either a weak reference (or it's smart-pointer equivalent).
Here is a Python doc for weak reference:
https://docs.python.org/3/library/weakref.html
So the code could look like this:
import weakref
shape_register = weakref.WeakValueDictionary()
class Shape(object):
# Create based on class name:
def factory(type):
#return eval(type + "()")
if type == "Circle":
instance = Circle()
shape_register[id(instance)] = instance
return instance
if type == "Square":
instance = Square()
shape_register[id(instance)] = instance
return isinstance
assert 0, "Bad shape creation: " + type
factory = staticmethod(factory)
class Circle(Shape):
def draw(self): print("Circle.draw")
def erase(self): print("Circle.erase")
class Square(Shape):
def draw(self): print("Square.draw")
def erase(self): print("Square.erase")
And the use:
>>> s = Shape.factory("Circle")
>>> shape_register.valuerefs()
[<weakref at 0x00000000037830F8; to 'Circle' at 0x0000000003773C18>]
^ You can see that the Circle instance in in the register.
>>> s = Shape.factory("Circle")
>>> shape_register.valuerefs()
[<weakref at 0x0000000003759F10; to 'Circle' at 0x00000000037737F0>]
^ A new instance was created, you can no longer access the original one. It was garbage collected and doesn't show in the register anymore.
>>> c = Shape.factory("Circle")
>>> shape_register.valuerefs()
[<weakref at 0x0000000003759F10; to 'Circle' at 0x00000000037737F0>, <weakref at 0x00000000037830F8; to 'Circle' at 0x0000000003773C18>]
>>>
^ However now another circle was created and stored in different variable. Both s and c are now accessible and the register shows two values.