ExtensionClass
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.
Common errors
-
AttributeError: 'SomeClass' object has no attribute '__of__'
cause Attempting to use acquisition-like patterns, or expecting a class to participate in Zope-style acquisition, without it inheriting from `ExtensionClass.Base`.fixEnsure the class intended to use `__of__` (or `ComputedAttribute`, `MethodObject` for acquisition-aware behavior) explicitly inherits from `ExtensionClass.Base`: `class MyClass(Base): ...` -
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
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.fixRefactor 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.
Warnings
- gotcha 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.
- gotcha 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.
- breaking 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.
Install
-
pip install extensionclass
Imports
- Base
from ExtensionClass import Base
- ExtensionClass
from ExtensionClass import ExtensionClass
- ComputedAttribute
from ExtensionClass import ComputedAttribute
- Method
from ExtensionClass.MethodObject import Method
Quickstart
from ExtensionClass import Base
class Container(Base):
pass
class Item(Base):
def __init__(self):
self.visited = []
def __of__(self, parent):
# The __of__ method is called when an Item is accessed
# through a parent (acquisition-like behavior).
self.visited.append(parent)
return self
container = Container()
item = Item()
print(f"Initial item visited list: {item.visited}")
# Accessing item through container triggers __of__
container.item1 = item
accessed_item = container.item1
print(f"After accessing through container: {item.visited}")
# Accessing again demonstrates __of__ being called multiple times
accessed_item_again = container.item1
print(f"After accessing again: {item.visited}")