Acquisition
raw JSON → 6.2 verified Thu Apr 16 auth: no python
Acquisition is a mechanism that allows objects to obtain attributes from the containment hierarchy they're in. This foundational Zope library, currently at version 6.2, facilitates dynamic attribute lookup based on an object's position within a hierarchy or explicitly set context. While it does not have a fixed release cadence, it is actively maintained by the Zope Foundation.
pip install Acquisition Common errors
error AttributeError: 'ClassName' object has no attribute 'attribute_name' ↓
cause The requested attribute 'attribute_name' could not be found on the object itself, nor was it successfully acquired from its containment hierarchy or explicit context. This often means the attribute is missing, or the acquisition path is not correctly configured.
fix
Inspect the object's acquisition chain using
obj.aq_chain() to verify the available parents and their attributes. Ensure the attribute exists on one of the objects in the expected acquisition path. Use obj.aq_acquire(attribute_name, default=None) to safely test for acquirable attributes. error ModuleNotFoundError: No module named 'Acquisition' ↓
cause The 'Acquisition' library is not installed in the current Python environment, or the environment is not correctly activated.
fix
Install the library using pip:
pip install Acquisition. If using a virtual environment, ensure it is activated before installation and execution. error TypeError: descriptor '__of__' requires a 'ClassName' object but received a 'AnotherClass' object ↓
cause The `__of__` method, used to set acquisition context, expects an instance of an Acquisition-aware class (e.g., one that inherits from `Acquisition.Implicit` or `Acquisition.Explicit`). Providing an object of a different type will raise a TypeError.
fix
Ensure that both the object on which
__of__ is called and the object passed as its argument are instances of classes that properly support Acquisition, typically by inheriting from Acquisition.Implicit or Acquisition.Explicit. Warnings
gotcha C methods defined in extension base classes that define their own data structures cannot use acquired attributes. This is because acquisition wrapper objects do not conform to the data structures expected by these methods, leading to potential `AttributeError` or `TypeError` if invoked on an wrapped object. ↓
fix Avoid using Acquisition with C methods in extension base classes that rely on specific internal data structures. Consider refactoring to use Python methods or explicitly unwrapping the object (`obj.aq_base`) before calling C methods, though this removes acquisition capabilities for that call.
gotcha The behavior of acquisition can become complex due to subtle differences between 'acquiring from context' and 'acquiring from containment'. Misunderstanding these distinctions can lead to unexpected attribute resolution or attributes not being found. ↓
fix Carefully review the official documentation on explicit vs. implicit acquisition and the roles of `__of__` (context) and object containment. Debug acquisition paths using `obj.aq_chain()` to visualize the hierarchy and `obj.aq_base` to get the unwrapped object.
gotcha Over-reliance on implicit acquisition can make code harder to reason about and debug, as attribute sources are not immediately obvious. This can lead to unexpected side effects or performance overhead from dynamic lookups. ↓
fix Use acquisition judiciously for genuinely hierarchical patterns. For critical paths or where clarity is paramount, consider more explicit dependency injection or passing attributes directly rather than relying solely on the acquisition chain.
Imports
- Implicit wrong
import Acquisition.Implicitcorrectfrom Acquisition import Implicit - aq_acquire wrong
obj.aq_acquirecorrectfrom Acquisition import aq_acquire
Quickstart
from Acquisition import Implicit
class C(Implicit):
pass
a = C()
b = C()
a.color = "red"
# 'b' acquires 'color' from 'a' because 'a' is put into b's context
print(b.__of__(a).color)
class X(Implicit):
pass
x = X().__of__(b.__of__(a))
# 'x' acquires 'color' from 'a' through 'b'
print(x.color)