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?