Source code for tt.trees.tree_node
"""A node, and related classes, for use in expression trees."""
from ..definitions import MAX_OPERATOR_STR_LEN, OPERATOR_MAPPING
_DEFAULT_INDENT_SIZE = MAX_OPERATOR_STR_LEN + 1
[docs]class ExpressionTreeNode(object):
"""A base class for expression tree nodes."""
def __init__(self, symbol_name, l_child=None, r_child=None):
self._symbol_name = symbol_name
self._l_child = l_child
self._r_child = r_child
@property
def symbol_name(self):
"""The string operator/operand name wrapped in this node.
:type: :class:`str <python:str>`
"""
return self._symbol_name
@property
def l_child(self):
""" This node's left child; ``None`` indicates the absence of a child.
:type: :class:`ExpressionTreeNode`, optional
"""
return self._l_child
@property
def r_child(self):
""" This node's left child; ``None`` indicates the absence of a child.
:type: :class:`ExpressionTreeNode`, optional
"""
return self._r_child
[docs] def evaluate(self, input_dict):
"""Recursively evaluate this node.
This is an interface that should be defined in sub-classes.
:param input_dict: A dictionary mapping expression symbols to the value
for which they should be subsituted in expression evaluation.
:type input_dict: Dict{:class:`str <python:str>`: truthy}
.. note::
Node evaluation does no checking of the validity of inputs; they
should be check before being passed here.
:returns: The evaluation of the tree rooted at this node.
:rtype: :class:`bool <python:bool>`
"""
raise NotImplementedError(
'Expression tree nodes must implement `evaluate`.')
def __str__(self, depth=0, indent_size=_DEFAULT_INDENT_SIZE, stem_list=[]):
ret = ''
if depth > 0:
trunk = ('{}' + (indent_size - 1) * ' ') * (depth - 1)
trunk = trunk.format(*stem_list)
stem = '`' + (indent_size - 1) * '-'
ret += trunk + stem + self._symbol_name
else:
ret += self._symbol_name
ret += '\n'
if self.r_child is not None:
ret += self.r_child.__str__(
depth=depth+1,
indent_size=indent_size,
stem_list=stem_list + ['|'])
if self._l_child is not None:
ret += self._l_child.__str__(
depth=depth+1,
indent_size=indent_size,
stem_list=stem_list + [' '])
return ret
[docs]class BinaryOperatorExpressionTreeNode(ExpressionTreeNode):
"""An expression tree node for binary operators."""
def __init__(self, operator_str, l_child, r_child):
super(BinaryOperatorExpressionTreeNode, self).__init__(
operator_str, l_child, r_child)
self._operator = OPERATOR_MAPPING[operator_str]
@property
def operator(self):
"""The actual operator object wrapped in this node.
:type: :class:`BooleanOperator\
<tt.definitions.operators.BooleanOperator>`
"""
return self._operator
def evaluate(self, input_dict):
return self.operator.eval_func(
self.l_child.evaluate(input_dict),
self.r_child.evaluate(input_dict))
[docs]class UnaryOperatorExpressionTreeNode(ExpressionTreeNode):
"""An expression tree node for unary operators."""
def __init__(self, operator_str, l_child):
super(UnaryOperatorExpressionTreeNode, self).__init__(
operator_str, l_child)
self._operator = OPERATOR_MAPPING[operator_str]
@property
def operator(self):
"""The actual operator object wrapped in this node.
:type: :class:`BooleanOperator\
<tt.definitions.operators.BooleanOperator>`
"""
return self._operator
def evaluate(self, input_dict):
return self.operator.eval_func(
self.l_child.evaluate(input_dict))
[docs]class OperandExpressionTreeNode(ExpressionTreeNode):
"""An expression tree node for operands.
Nodes of this type will always be leaves in an expression tree.
"""
def __init__(self, operand_str):
super(OperandExpressionTreeNode, self).__init__(operand_str)
def evaluate(self, input_dict):
if self.symbol_name == '0':
return 0
elif self.symbol_name == '1':
return 1
else:
return input_dict[self.symbol_name]