Magic Parameters¶
Python’s *args
variable-number of arguments and **kwargs
keyword
arguments are sometimes called “magic” arguments. options
takes this up a
notch, allowing setters much like Python’s property
function or
@property
decorator. This allows arguments to be interpreted on the fly.
This is useful, for instance, to provide relative rather than just absolute
values. As an example, say that we added this code after Shape.options
was
defined:
options.magic(
height = lambda v, cur: cur.height + int(v) if isinstance(v, str) else v,
width = lambda v, cur: cur.width + int(v) if isinstance(v, str) else v
)
Now, in addition to absolute height
and width
parameters which are
provided by specifying int
(integer/numeric) values, your module
auto-magically supports relative parameters for height
and width
.:
one.draw(width='+200')
yields:
color='blue', width=210, name='one', height=10
This can be as fancy as you like, defining an entire domain-specific expression language.
But even small functions can give you a great bump in expressive power. For example,
add this and you get full relative arithmetic capability (+
, -
, *
, and /
):
def relmath(value, currently):
if isinstance(value, str):
if value.startswith('*'):
return currently * int(value[1:])
elif value.startswith('/'):
return currently / int(value[1:])
else:
return currently + int(value)
else:
return value
...
options.magic(
height = lambda v, cur: relmath(v, cur.height),
width = lambda v, cur: relmath(v, cur.width)
)
Then:
one.draw(width='*4', height='/2')
yields:
color='blue', width=40, name='one', height=5
Magically interpreted parameters are the sort of thing that one doesn’t need very often or for every parameter–but when they’re useful, they’re enormously useful and highly leveraged, leading to much simpler, much higher function APIs.
We call them ‘magical’ here because of the “auto-magical” interpretation, but they are really just analogs of Python object properties. The magic function is basically a “setter” for a dictionary element.