1

I have a ModelManager which keeps track of creating and destroying new objects. Here's an example:

class ModelManager:
    MAX_OBJECTS = 10
    OBJECTS = {} # hash to model object
    NUM_OBJECTS = len(OBJECTS) # how to dynamically calculate this?

Every time an object is created it is added to OBJECTS and everytime it is deleted it gets popped from OBJECTS.

How would I properly do the NUM_OBJECTS here? Ideally it should be a classmethod/property to act as a calculation. For doing something like the above, what would be the best way?

I would like to call it as ModelManager.NUM_OBJECTS

David542
  • 104,438
  • 178
  • 489
  • 842

1 Answers1

2

Use a computed property

class ModelManager:

    @property
    def NUM_OBJECTS(self):
        return len(self.OBJECTS)

Also, note that OBJECTS will be shared across your class instances because it is a dictionary initialized at class scope. The NUM_OBJECT property requires initializing the class. If you want NUM_OBJECTS to be a property of the class, use one of the solutions suggested here for class properties.

If you would rather be able to call len around your class (in addition to NUM_OBJECTS) - you can overkill with metaclasses:

class ModelManagerMeta(type):

    def __len__(cls):
         return len(cls.OBJECTS)

    def NUM_OBJECTS(cls):
         return len(cls.OBJECTS)


class ModelManager(metaclass=ModelManagerMeta):

    MAX_OBJECTS = 10
    OBJECTS = {} # hash to model object
    ...
modesitt
  • 7,052
  • 2
  • 34
  • 64
  • right, but then I'd need to call it as `ModelManager().NUM_OBJECTS`. I'm just using it as a class manager, so calling it as `ModelManager.NUM_OBJECTS`. – David542 Oct 16 '19 at 01:36
  • 1
    @David542: You'll have a much smoother experience if you don't try to make a class do an instance's job. – user2357112 Oct 16 '19 at 01:40
  • @user2357112 what would be a better way to do the above then? – David542 Oct 16 '19 at 01:41
  • 2
    Make an instance instead of using the class directly. You can make it a module-level global if you really want. – user2357112 Oct 16 '19 at 01:42
  • 1
    @user2357112 do you mean something like: `manager=ModelManager()` at the top, and then just use that? – David542 Oct 16 '19 at 01:43
  • 1
    @user2357112 is right. Otherwise, you will probably have to implement most of your "class" in the meta class above for it to work as desired. This code is confusing and an abuse of metaclasses (imo) – modesitt Oct 16 '19 at 01:43
  • 1
    @David542: Pretty much. – user2357112 Oct 16 '19 at 01:43