import time
[docs]class Counter:
def __init__(self, start=0, step=1):
self._count = start
self._start = start
self._step = step
[docs] def count(self):
"""
Move counter forward by ``step``
"""
self._count += self._step
[docs] def get(self):
"""
Get the internal number of counter.
"""
return self._count
[docs] def reset(self):
"""
Reset the counter.
"""
self._count = self._start
def __lt__(self, other):
return self._count < other
def __gt__(self, other):
return self._count > other
def __le__(self, other):
return self._count <= other
def __ge__(self, other):
return self._count >= other
def __eq__(self, other):
return self._count == other
def __repr__(self):
return "%d" % self._count
[docs]class Switch:
def __init__(self, state: bool = False):
"""
Args:
state: Internal state, ``True`` for on, ``False`` for off.
"""
self._on = state
[docs] def flip(self):
"""
Inverse the internal state.
"""
self._on = not self._on
[docs] def get(self) -> bool:
"""
Returns:
state of switch.
"""
return self._on
[docs] def on(self):
"""
Set to on.
"""
self._on = True
[docs] def off(self):
"""
Set to off.
"""
self._on = False
[docs]class Trigger(Switch):
[docs] def get(self):
"""
Get the state of trigger, will also set trigger to off.
Returns:
state of trigger.
"""
on = self._on
if self._on:
self._on = False
return on
[docs]class Timer:
def __init__(self):
self._last = time.time()
[docs] def begin(self):
"""
Begin timing.
"""
self._last = time.time()
[docs] def end(self):
"""
Returns:
Curent time difference since last ``begin()``
"""
return time.time() - self._last
[docs]class Object:
"""
An generic object class, which stores a dictionary internally, and you
can access and set its keys by accessing and seting attributes of the
object.
Attributes:
data: Internal dictionary.
"""
def __init__(self, data=None, const_attrs=None):
if data is None:
data = {}
if const_attrs is None:
const_attrs = set()
super(Object, self).__setattr__("const_attrs", const_attrs)
super(Object, self).__setattr__("data", data)
def __call__(self, *args, **kwargs):
return self.call(*args, **kwargs)
[docs] def call(self, *args, **kwargs):
"""
the implementation of ``Object.__call__``, override it to
customize call behavior.
"""
pass
def __getattr__(self, item):
# This function will be called if python cannot find an attribute
# Note: in order to make Object picklable, we must raise AttributeError
# when looking for special methods, such that when pickler is looking
# up a non-existing __getstate__ function etc, this class will
# not return a None value because self.attr(item) will return None.
if isinstance(item, str) and item[:2] == item[-2:] == '__':
# skip non-existing special method lookups
raise AttributeError("Failed to find attribute: {}"
.format(item))
return self.attr(item)
def __getitem__(self, item):
return self.attr(item)
def __setattr__(self, key, value):
if (key != "data" and key != "attr" and
key != "call" and key not in self.__dir__()):
if key in self.const_attrs:
raise RuntimeError("{} is const.".format(key))
self.attr(key, value, change=True)
elif key == "call":
super(Object, self).__setattr__(key, value)
elif key == "data":
if isinstance(value, dict):
super(Object, self).__setattr__(key, value)
else:
raise ValueError("The data attribute must be a dictionary.")
else:
raise RuntimeError("You should not set the {} property of an "
"Object. You can only set non-const keys "
"in data and .data and .call attributes."
.format(key))
def __setitem__(self, key, value):
self.__setattr__(key, value)
[docs] def attr(self, item, value=None, change=False):
if change:
self.data[item] = value
return self.data.get(item, None)