2.2.1.2 binding.Attribute - The Basis for all Bindings

All PEAK bindings are created using the class binding.Attribute, or a subclass thereof. It provides the basic machinery needed to lazily compute an attribute "on-the-fly". Here's a simple example of its use:

class Car(binding.Component):

    def height(self):
        baseHeight = self.roof.top - self.chassis.bottom
        return self.wheels.radius + baseHeight

    height = binding.Make(height)

In this example, we want to compute the car's height based on various other attributes, but we only want to compute it once, and save the value thereafter. To do this, we define a function that takes three arguments: the object, its instance dictionary, and the name of the attribute being computed. Most of the time, you'll only care about the first argument, which is the object for which the attribute is being computed. It's rare that you'll need the instance dictionary or the attribute name, but if you need them, they're there. Normally, you'll just return the value you want the attribute to end up with.

Note, by the way, that there's no need for this function passed to binding.Once to be a method, or for the parameters to have specific names. If we continued the class above as follows:

    verticalCenter = binding.Once(lambda self: self.height/2)

This would be a perfectly valid way to express the idea that the car's vertical center is half of its height. It's also true that we could say:

    passengers = binding.Once(lambda: {})

as another way of saying "binding.Make(dict)". However, using "binding.Make(dict)" is more compact, and clearer as to intention.

By the way, although we've been only showing uses of binding.Make with one argument (the function to be called), binding.Make does actually take other arguments, such as a default attribute name, an ``offer as" specification (more on this later) and a docstring. Check out the PEAK API Reference or the source code for more details.