[Edu-sig] the Descriptor pattern (new wrinkle in 3.6+)

kirby urner kirby.urner at gmail.com
Mon Dec 19 14:01:41 EST 2016


What I like about staying the course on the 3.x track (versus adhering to
the 2.7 terminus of the 2.x line), is each new version is an opportunity to
catch up on features that have joined over several versions.  My capacity
to catch up inevitably lags the actual path of Python's evolution, not a
tragedy, an opportunity.

For example, I've recently pushed a lot more into Descriptor territory and
in my last class for adults, spent time with a Python source code
implementation of the property callable.  As a built-in, it's written in C,
however what it does may be modeled in pure Python.  You may be familiar
with this passage.  Here's a Jupyter Notebook:

https://github.com/4dsolutions/Python5/blob/master/Descriptors%20and%20Properties.ipynb

The Property class is what's critical.  I then use it to decorate code in
other modules, proving that the pure Python class and the builtin do the
same work.  I've shared my "Prop Circle" before (since adding
circumference, the logical next step):

"""
Created on Thu Oct 20 15:43:14 2016
Modified Wed Dec 7, 2016

@author: Kirby Urner

Related reading:
https://mail.python.org/pipermail/edu-sig/2016-October/011548.html
"""

from model_property import Property as property
import math

class Circle:
    """setting either the radius or area attribute sets the other
       as a dependent value.  Initialized with radius only, unit
       circle by default.
    """

    def __init__(self, radius = 1):
        self.radius = radius

    @property
    def area(self):
        return self._area

    @property
    def radius(self):
        return self._radius

    @property
    def circumference(self):
        return self._circum

    @circumference.setter
    def circumference(self, value):
        self.radius = value / (2 * math.pi)

    @area.setter
    def area(self, value):
        self._area = value
        self._radius = math.sqrt(self._area / math.pi)
        self._circum = 2 * math.pi * self._radius

    @radius.setter
    def radius(self, value):
        self._radius = value
        self._area = math.pi * (self._radius ** 2)
        self._circum = 2 * math.pi * self._radius

    def __repr__(self):
        return "Circle(radius = {})".format(self.radius)

# Circle may be imported from prop_circle without all this noise.
if __name__ == "__main__":
    the_circle = Circle(5)
    print("the_circle:", the_circle)
    print("Area: ", the_circle.area)
    the_circle.area = 50
    print("Radius when Area=50:", the_circle.radius)

I'm also experimenting with new namepaces for terminology,
though in general I'm quite happy with the Python lingo.
A Descriptor is this miniature unit of bookkeeping, wherein reading and
writing operations, also being named at birth, register within the guts of
the thing, triggering __set__ and __get__ (and now __set_name__).

What if I use the word "Clerk" for "Descriptor" in some passages, and
picture something Monty Pythonesque from a Charles Dickens like milieu.
For a specific Lesson Plan, such imagery might reinforce comprehension of
design pattern possibilities.

A class (type) may wish to contract out come of its attributes to this
professional bookkeeping class, called a Clerk, actually a Descriptor, that
has reprogrammable behavior around setting and getting a value.

Introduce these to your own classes as class-level inclusions if you wish.
Compose, don't subclass.

Don't worry though: when these clerk-monitored attributes are actually used
by your instances, that instance will be a known object, passed in to the
Clerk, and usable as part of a key to keep values specific to where they
came from right down to the instance level.

IF that's your goal.

Blog post that's more casual, with some screen shots
showing source code.

http://controlroom.blogspot.com/2016/12/back-on-that-python-train.html

Kirby
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/edu-sig/attachments/20161219/194da12d/attachment.html>


More information about the Edu-sig mailing list