Table of Contents

Class: Descriptor ./src/peak/binding/once.py

Attribute descriptor with lazy initialization and caching

A Descriptor (or subclass) instance is a Python attribute descriptor, similar to the ones created using the Python property built-in type. However, where property instances invoke a function on every access to the attribute, binding.Descriptor instances only call their computeValue() method once, caching the result in the containing object's dictionary. Thereafter, the value in the dictionary is reused, instead of calling the function each time. If the attribute is deleted (e.g. via del anObj.anAttr) or the value is cleared from the dictionary, the computeValue() method will be called again, the next time that the attribute is retrieved.

Because the instance dictionary is used to store the attribute value, a Descriptor needs to know its name, so that it knows what key to store its value under. Unfortunately, Python does not provide a way for descriptors to know what name(s) they are accessible under in a class, so you must explicitly provide an attrName value, either as a constructor keyword argument, or by defining it in a subclass. Many Descriptor subclasses have the ability to guess or detect what attrName should be used, but you must still explicitly provide it if they are unable to do so automatically. Failure to supply a correct attrName will result in a TypeError when the attribute is used.

Descriptor instances have the following attributes which may be set by keyword arguments to the class' constructor:

attrName
sets the name which the descriptor will use to get/set its value in the instance dictionary. Ordinarily this should be the same as the name given to the descriptor in its containing class, but you may occasionally wish it to be something else.
computeValue(obj, instDict, attrName)
a function that will be called whenever the attribute is accessed and no value for the attribute is present in the object's instance dictionary. The function will be passed three arguments: the object that owns the attribute, the object's instance dictionary, and the descriptor's attrName.

The value returned will be treated as the attribute's value. It will also be cached in the object's instance dictionary to avoid repeat calls, unless the descriptor's noCache attribute is True.

Note that the default implementation of computeValue() simply raises an AttributeError. Also note that the call signature of computeValue() is the same as that of binding.IRecipe. That is, any object that provides IRecipe may be used as a computeValue attribute. Descriptor does not perform any adaptation, however, so if your desired object must be adapted to IRecipe, you should do so before assigning it to the computeValue attribute.

noCache
if set to True, the descriptor will not cache its computeValue() results in the owning object's instance dictionary. This makes the descriptor's behavior more similar to the Python property type. But, computeValue() will not be called when the attribute is currently set (i.e., a value is in the object's instance dictionary under attrName), so the behavior is still quite different from the property type.
onSet(obj, attrName, value)
a function that will be called whenever the attribute is set, or when the result of computeValue() is to be cached. The function will be passed three arguments: the object that owns the attribute, the descriptor's attrName, and the value that is to be set. The function may return the passed-in value, or change it by returning a different value. To prevent the value from being set, the function should raise an exception. If you do not set this attribute, its default implementation simply returns the value unmodified.
ofClass(attrName, klass)
a function that will be called whenever the descriptor is retrieved from its class. The default implementation simply returns the descriptor.
permissionNeeded
a peak.security.IAbstractPermission, or None. This is a convenience feature for use with the peak.security package.

You can override the methods described above in subclasses. Keep in mind, however, that you will then need to add a self parameter in addition to the ones described above. The self argument will refer to the Descriptor instance.

The Descriptor class is rarely used directly; normally you will use one of its subclasses, which have many additional features for more convenient use. However, many of those subclasses themselves use Descriptor instances as part of their definition. That's why this exists as a separate base class: to make it possible to use descriptors as part of the definition of descriptor classes.

Base Classes   
BaseDescriptor
Methods   
__init__
  __init__ 
__init__ ( self,  **kw )

Create a descriptor from keyword arguments

You may pass any keyword arguments, as long as they represent existing attributes defined by the Descriptor class (or subclass, if this constructor is used by the subclass).


Table of Contents

This document was automatically generated on Mon Jan 27 01:11:03 2025 by HappyDoc version 2.1