Slots for class objects? (i.e. avoiding creating __dict__ for classes themselves)

Hi there,

I am working on a data-oriented library that uses classes much like any other object instance, and can generate large numbers (tens of thousands, if not low hundreds of thousands) of classes at runtime, by calling the invoking (i.e. effectively by invoking the 3-arg form of type()).

I’m looking for ways of cutting down the memory consumption of the library in general. As part of that I have the dynamically generated classes (and their parent classes) set up with __slots__, so that class instances avoid the overhead of having a __dict__ attribute and associated dict instance, and that has helped. However since the number of classes can be the same as or more than the number of instances, I figure it’s probably worth the classes themselves having slots, for the same reason. However, I can’t figure out how to do that.

Adding __slots__ to the metaclass doesn’t help:

mjog@sable:~$ python3
Python 3.10.7 (main, Nov  2 2022, 18:49:29) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class Meta(type): __slots__ = ()
... 
>>> # Doesn't work for a static class
>>> class Foo(metaclass=Meta): __slots__ = ()
... 
>>> getattr(Foo, '__dict__')
mappingproxy({'__module__': '__main__', '__slots__': (), '__doc__': None})
>>> # Doesn't work for a dynamic class either
>>> Bar = Meta('Bar', (), {})
>>> getattr(Bar, '__dict__')
mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Bar' objec

And looking at the docs about metaclasses, it seems like there will always be a __dict__ assigned:

When a new class is created by type.__new__, the object provided as the namespace parameter is copied to a new ordered mapping and the original object is discarded. The new copy is wrapped in a read-only proxy, which becomes the __dict__ attribute of the class object.

I guess the fact that the 3-arg form of type() requires a dict to be passed in as the third arg implies classes will always have a __dict__ attribute?

Am I out of luck here?