editabletuple
Overview
This module provides the editabletuple()
and editableobject()
functions.
The editabletuple()
function is used tor creating classes with a fixed
sequence of fields, similar to a namedtuple, except editable.
Each instance of a class created by the editabletuple()
function's fields
can be accessed by index et[i]
(or by slice), or by fieldname et.name
.
Although fields can be read and written, they cannot be added or deleted.
Since instances are mutable they can't be used in sets or as dict keys.
If you provide a validator, it will be used when new instances are created
and updated.
The editableobject()
function creates classes very similar to those
created by editabletuple()
. The essential difference is that
editableobject()
's class's instances don't support indexing or
iteration, so support only fieldname access. They also have an addtional
totuple
property (not needed for editabletuple()
s since tuple(et)
is
sufficient due to their iteration support).
See the function docstrings for examples and more about the editabletuple
and editableobject APIs.
To install just use python3 -m pip install editabletuple
. (See
PyPI.)
Or just copy the editabletuple.py
file which is self-contained and depends
only on the standard library.
Examples
Example #1: no defaults; no validator
>>> Options = editabletuple('Options', 'maxcolors shape zoom restore')
>>> options = Options(5, 'square', 0.9, True)
>>> options
Options(maxcolors=5, shape='square', zoom=0.9, restore=True)
>>> options.maxcolors = 7
>>> options[-1] = False
>>> options[2] -= 0.1
>>> options
Options(maxcolors=7, shape='square', zoom=0.8, restore=False)
Example #2: with defaults but no validator
>>> Rgb = editabletuple('Rgb', 'red green blue', defaults=(0, 0, 0))
>>> black = Rgb()
>>> black
Rgb(red=0, green=0, blue=0)
>>> navy = Rgb(blue=128)
>>> navy
Rgb(red=0, green=0, blue=128)
>>> violet = Rgb(238, 130, 238)
>>> violet
Rgb(red=238, green=130, blue=238)
Example #3: with defaults and a validator
If you provide a validator function, it will be called whenever an attempt
is made to set a value, whether at construction time or later by et[i] = value
or et.fieldname = value
. It is passed an attribute name
and an
attribute value
. It should check the value and either return the value (or
an acceptable alternative value) which will be the one actually set, or
raise a ValueError
.
>>> def validate_rgba(name, value):
... if name == 'alpha':
... if not (0.0 <= value <= 1.0):
... return 1.0 # silently default to opaque
... elif not (0 <= value <= 255):
... raise ValueError(f'color value must be 0-255, got {value}')
... return value # must return a valid value or raise ValueError
>>>
>>> Rgba = editabletuple('Rgba', 'red', 'green', 'blue', 'alpha',
... defaults=(0, 0, 0, 1.0), validator=validate_rgba)
>>> black = Rgba()
>>> black
Rgba(red=0, green=0, blue=0, alpha=1.0)
>>> seminavy = Rgba(blue=128, alpha=0.5)
>>> seminavy
Rgba(red=0, green=0, blue=128, alpha=0.5)
>>> violet = Rgba(238, 130, 238, alpha=2.5) # alpha too big
>>> violet
Rgba(red=238, green=130, blue=238, alpha=1.0)
>>>
>>> color = Rgba(green=99)
>>> color
Rgba(red=0, green=99, blue=0, alpha=1.0)
>>> assert color.green == 99
>>> color.red = 128
>>> assert color[2] == 0
>>> color[2] = 240
>>> assert color[2] == 240
>>> color[-1] = 0.5
>>> color
Rgba(red=128, green=99, blue=240, alpha=0.5)
>>> color[1] = 299
Traceback (most recent call last):
...
ValueError: color value must be 0-255, got 299
>>> color.blue = -65
Traceback (most recent call last):
...
ValueError: color value must be 0-255, got -65
These examples—and several others—are in the module's function's
docstrings.
API
def editabletuple(classname, *fieldnames, defaults=None, validator=None, doc=None):
Creates a new class called classname
with the given fieldnames
, optional
defaults
, optional validator
, and optional doc
docstring.
Instances of the class behave almost exactly like
collections.namedtuple
's except that fields may be set as well as get
using their index position or fieldname. They support len()
, in
, the
comparison operators, and are iterable—which means they can be converted to
a list
or tuple
by passing to either's eponymous factory function. They
also provide an .asdict
property, and also an update()
method that
accepts name=value
arguments.
def editableobject(classname, *fieldnames, defaults=None, validator=None, doc=None):
Creates a new class called classname
with the given fieldnames
, optional
defaults
, optional validator
, and optional doc
docstring.
Instances of the class have fields which can get and set by fieldname. They
support the comparison operators and .astuple
and .asdict
properties,
the former returning a tuple
of the instance's values, the latter a dict
of fielname-value items. It also has an update()
method that accepts
name=value
arguments.
Notes
I can't work out how to make editabletuple
and editableobject
instances picklable. Patches or suggestions on how to do this would be
welcome.
License: GPLv3