#!/usr/bin/env python # encoding: utf-8 from .render import Renderable from decimal import Decimal from .generic import transpose_fill class Explicable(Renderable): """ An Explicable object is an object which can be explicable! It's a parent class of a more classical Expression, Fraction and Polynom (and later square root) Child class will have the following method * explain: Generator which return steps which leed to himself """ def __init__(self, *args, **kwargs): super(Explicable, self).__init__() self.steps = [] def explain(self, noself=True): r""" Generate and render steps which leed to itself :param noself: does explain return self >>> action = Explicable() >>> from .expression import Expression >>> action.postfix_tokens = Expression('42') >>> action.this_append_before([Expression('2+10*4'), Expression('2+40')]) >>> for i in action.explain(): ... print(i) 2 + 10 \times 4 2 + 40 42 """ old_s = '' # les étapes pour l'atteindre try: for s in self.steps: try: new_s = self.STR_RENDER(s.postfix_tokens) except AttributeError: new_s = self.STR_RENDER(s) if not self.is_same_step(new_s, old_s): old_s = new_s yield new_s except AttributeError: pass if noself: # Lui même new_s = self.STR_RENDER(self.postfix_tokens) if not self.is_same_step(new_s, old_s): yield new_s def is_same_step(self, new, old): """Return whether the new step is the same than old step """ try: if new.replace(" ", "") == old.replace(" ", ""): return True else: return False except AttributeError: if new == old: return True else: return False def this_append_before(self, steps): """ Add steps at the beginning of self.steps :param steps: list of steps that append before >>> e = Explicable() >>> s = ['eat', 'sleep'] >>> e.this_append_before(s) >>> print(e.steps) ['eat', 'sleep'] >>> s0 = ['cook'] >>> e.this_append_before(s0) >>> print(e.steps) ['cook', 'eat', 'sleep'] """ self.steps = steps + self.steps @staticmethod def merge_history(expl1, expl2, operation): """ Take two Explicable objects, explain where they are from and merge their history /!\ Using this method make the two objects amnesiac :param expl1: fist explicable :param expl2: second explicable :param operation: the operation that link them :returns: the list of steps >>> from .expression import Expression >>> from .operator import op >>> action1 = Explicable() >>> action1.postfix_tokens = Expression('42') >>> action1.this_append_before([Expression('2+10*4'), Expression('2+40')]) >>> action2 = Explicable() >>> action2.postfix_tokens = Expression('24') >>> action2.this_append_before([Expression('2*12')]) >>> m_history = Explicable().merge_history(action1, action2, op.add) >>> m_history >>> for i in m_history: ... print(i) ['2 + 10 \\times 4', '2 \\times 12', +] ['2 + 40', '24', +] ['42', '24', +] """ steps1 = list(expl1.explain()) steps2 = list(expl2.explain()) return transpose_fill([steps1, steps2, [operation]]) class Explicable_int(int, Explicable): """ An Explicable_int is an int which can be explain """ isNumber = True def __init__(self, val): super(Explicable_int, self).__init__(val) self._val = val self.postfix_tokens = [self] self.steps = [] def simplify(self): return Explicable_int(self._val) def __txt__(self): return str(self._val) def __tex__(self): return str(self._val) class Explicable_Decimal(Decimal, Explicable): """ An Explicable_Decimal is an decimal which can be explain """ isNumber = True def __init__(self, val): super(Explicable_Decimal, self).__init__(val) self._val = val self.postfix_tokens = [self] self.steps = [] def simplify(self): return Explicable_Decimal(self._val) def __txt__(self): return str(self._val) def __tex__(self): return str(self._val) # ----------------------------- # Reglages pour 'vim' # vim:set autoindent expandtab tabstop=4 shiftwidth=4: # cursor: 16 del