{"id":8982,"library":"extensionclass","title":"ExtensionClass","description":"This package provides a metaclass that allows classes implemented in extension modules (typically written in C) to be subclassed in Python. It's primarily used in legacy Python applications, notably within the Zope and Plone ecosystems, to provide features like a class initializer (`__class_init__`) and the acquisition-oriented `__of__` protocol, which predates some modern Python features. The current version is 6.2 and it is actively maintained by the Zope Foundation.","status":"active","version":"6.2","language":"en","source_language":"en","source_url":"https://github.com/zopefoundation/ExtensionClass","tags":["metaclass","zope","legacy","acquisition","c-extension"],"install":[{"cmd":"pip install extensionclass","lang":"bash","label":"PyPI"}],"dependencies":[],"imports":[{"symbol":"Base","correct":"from ExtensionClass import Base"},{"symbol":"ExtensionClass","correct":"from ExtensionClass import ExtensionClass"},{"note":"For attaching computed attributes to ExtensionClass instances","symbol":"ComputedAttribute","correct":"from ExtensionClass import ComputedAttribute"},{"note":"For creating callable method objects bound to ExtensionClass instances","symbol":"Method","correct":"from ExtensionClass.MethodObject import Method"}],"quickstart":{"code":"from ExtensionClass import Base\n\nclass Container(Base):\n    pass\n\nclass Item(Base):\n    def __init__(self):\n        self.visited = []\n\n    def __of__(self, parent):\n        # The __of__ method is called when an Item is accessed\n        # through a parent (acquisition-like behavior).\n        self.visited.append(parent)\n        return self\n\ncontainer = Container()\nitem = Item()\n\nprint(f\"Initial item visited list: {item.visited}\")\n\n# Accessing item through container triggers __of__\ncontainer.item1 = item\naccessed_item = container.item1\n\nprint(f\"After accessing through container: {item.visited}\")\n\n# Accessing again demonstrates __of__ being called multiple times\naccessed_item_again = container.item1\nprint(f\"After accessing again: {item.visited}\")","lang":"python","description":"This example demonstrates the core `ExtensionClass.Base` and its `__of__` protocol, which is central to Zope's acquisition system. When an instance of `Item` is accessed via `container.item1`, the `__of__` method on `Item` is invoked, receiving the `container` as its `parent` argument."},"warnings":[{"fix":"Evaluate if standard Python class mechanisms (e.g., properties, descriptors, `__slots__`, mixins, or standard inheritance) can achieve the desired outcome without `ExtensionClass`.","message":"For new Python projects, `ExtensionClass` is largely superseded by standard Python 'new-style' classes (available since Python 2.2) which offer similar capabilities for extending classes and often better integrate with modern Python patterns. Unless specifically working with Zope/Plone or similar legacy systems, native Python features are usually preferred.","severity":"gotcha","affected_versions":"All"},{"fix":"Thoroughly understand Zope's acquisition documentation if utilizing `__of__`. Be explicit about object references and their lifetimes to avoid unintended side effects from re-parenting.","message":"The `__of__` protocol implements 'acquisition', a specific object traversal and context-setting pattern. Misunderstanding how `__of__` binds and rebinds objects can lead to unexpected state or object graph complexities, particularly when objects are referenced from multiple parents or contexts.","severity":"gotcha","affected_versions":"All"},{"fix":"Ensure `extensionclass` is updated to version 4.4 or higher to benefit from compilation fixes and improved platform compatibility.","message":"Older versions (prior to 4.4) had known issues where C extensions might fail to compile on compatible platforms, leading to installation failures or runtime errors if the pure-Python fallback was not robust.","severity":"breaking","affected_versions":"<4.4"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Ensure the class intended to use `__of__` (or `ComputedAttribute`, `MethodObject` for acquisition-aware behavior) explicitly inherits from `ExtensionClass.Base`: `class MyClass(Base): ...`","cause":"Attempting to use acquisition-like patterns, or expecting a class to participate in Zope-style acquisition, without it inheriting from `ExtensionClass.Base`.","error":"AttributeError: 'SomeClass' object has no attribute '__of__'"},{"fix":"Refactor the class hierarchy to ensure a single, compatible metaclass is used, or explicitly define a custom metaclass that correctly inherits from all necessary base metaclasses. In modern Python 3, directly assigning `__metaclass__` is less common than inheriting from `type` or another metaclass directly.","cause":"This error occurs in Python when a class attempts to inherit from multiple bases that have incompatible metaclasses. While not unique to `ExtensionClass`, it can arise if `ExtensionClass.ExtensionClass` is used as a `__metaclass__` alongside another class that implicitly defines a different metaclass.","error":"TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases"}]}