diff options
| author | Jason Madden <jamadden@gmail.com> | 2020-01-23 11:38:41 -0600 |
|---|---|---|
| committer | Jason Madden <jamadden@gmail.com> | 2020-01-23 11:38:41 -0600 |
| commit | 72dc05b90fb26385f0ad100376e0875439825da8 (patch) | |
| tree | 6e8a8ddb202f76cb1dad8b90a1ee077a5f0bf752 | |
| parent | cacd85b78d530336136cac40c42019b8b6946eb0 (diff) | |
| download | zope-interface-slots.tar.gz | |
Avoid allocating space for tagged values unless they're used. This saves another few percent.slots
| -rw-r--r-- | CHANGES.rst | 10 | ||||
| -rw-r--r-- | src/zope/interface/interface.py | 12 |
2 files changed, 19 insertions, 3 deletions
diff --git a/CHANGES.rst b/CHANGES.rst index c5de832..b976ba1 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -17,6 +17,16 @@ an undocumented private C API function, and helps make some instances require less memory. See `PR 154 <https://github.com/zopefoundation/zope.interface/pull/154>`_. +- Reduce memory usage in other ways based on observations of usage + patterns in Zope (3) and Plone code bases. + + - Specifications with no dependents are common (more than 50%) so + avoid allocating a ``WeakKeyDictionary`` unless we need it. + - Likewise, tagged values are relatively rare, so don't allocate a + dictionary to hold them until they are used. + + The changes in this release resulted in a 7% memory reduction after + loading about 6,000 modules that define about 2,200 interfaces. 4.7.1 (2019-11-11) ================== diff --git a/src/zope/interface/interface.py b/src/zope/interface/interface.py index c374cef..f501077 100644 --- a/src/zope/interface/interface.py +++ b/src/zope/interface/interface.py @@ -67,7 +67,9 @@ class Element(object): self.__name__ = __name__ self.__doc__ = __doc__ - self.__tagged_values = {} + # Tagged values are rare, especially on methods or attributes. + # Deferring the allocation can save substantial memory. + self.__tagged_values = None def getName(self): """ Returns the name of the object. """ @@ -79,18 +81,22 @@ class Element(object): def getTaggedValue(self, tag): """ Returns the value associated with 'tag'. """ + if not self.__tagged_values: + raise KeyError(tag) return self.__tagged_values[tag] def queryTaggedValue(self, tag, default=None): """ Returns the value associated with 'tag'. """ - return self.__tagged_values.get(tag, default) + return self.__tagged_values.get(tag, default) if self.__tagged_values else default def getTaggedValueTags(self): """ Returns a list of all tags. """ - return self.__tagged_values.keys() + return self.__tagged_values.keys() if self.__tagged_values else () def setTaggedValue(self, tag, value): """ Associates 'value' with 'key'. """ + if self.__tagged_values is None: + self.__tagged_values = {} self.__tagged_values[tag] = value |
