This example implementation is extremely similar to what is being asked and answered on the following stack overflow page: http://stackoverflow.com/questions/1325673/how-to-add-property-to-a-python-class-dynamically
I have drawn a story to illustrate the resulting functionality of the AppleInterface, which works as though the attributes of Apple were it's own, and as if each of those attributes had been explicitly defined in the script.
There is an apple in a grass lawn in a small town. It has has a weight of 1 and is ripe. This apple is defined as follows
>>> apple_instance = Apple(1, True)
Our adventure starts when we wander outside our home and notice this apple. We will pick it up to investigate it. We are not an apple, so our interactions with the apple will be done through an interface.
>>> apple = AppleInterface(apple_instance)
===== Creating interface for Apple =====
Defining default get/set for attribute 'weight'.
Defining default get/set for attribute 'ripe'.
Attribute 'category' already exists.
========================================
With the apple interface, we can find the weight of the apple, and can see that it is ripe. However, we do not know what kind of apple it is.
>>> get_apple_weight(apple)
This apple weighs 1 units.
>>> get_apple_ripeness(apple)
This apple is ripe.
>>> get_apple_category(apple)
The type of apple is: unknown
We ask around town, and a local merchant claims that it is a "dragon apple". Though perposterous sounding, he is insistant, so we will try to set the category.
>>> set_apple_category(apple, "dragon apple")
Apple type of 'dragon apple' does not exist.
Attempting to set the value fails, because the category
attribute of the AppleInterface has been manually defined to verify that the value is contained within a pre-set list of possible categories (we could simple observer AppleInterface.allowed_categories
, but that defeats the purpose of this example).
We decide to go on a quest to identify this type of apple, as it is foreign to this land. We set out and after a 3 week journey, come across an elder with an auroa of wisdom about himself. He claims the apple is a Fuji apple, though it is no longer ripe after the long journey.
>>> apple.ripe = False
>>> set_apple_category(apple, "fuji")
The type of apple is: fuji
It is a Fuji apple, as the elder claimed.
In this journey we have read attributes of a class that were not manually defined, and were therefore defined with default get
and set
methods that would read and write values associated with an attribute of the same name from a "storage instance". That instance in this case was a simple class (Apple) that contained only attributes, but represents more complicated classes facilitating reading/writing data to more complicated storage mechanisms (databases for example).
In the case of the category attribute, we needed to execute some input validation before passing the provided value to storage. To facilitate this, we manually defined a get
and set
method in the AppleInterface class. Though the get
method is the same as the otherwise default get
method, the set
method we defined will verify that the provided value by ensuring it is one of the strings in the class attribute list allowed_categories
.