1. 程式人生 > >python 初探狀態機transitions庫

python 初探狀態機transitions庫


接著繼續在add_model()中:
    for trigger, _ in self.events.items():
        self._add_trigger_to_model(trigger, model)
這個是遍歷我們Machine例項中的self.events的鍵值對,拿到每個觸發名字:to_liquid, to_solid, to_gas, to_plasma, melt, ionize, sublimate, evaporate,遍歷呼叫self._add_trigger_to_model(trigger, model):
    def _add_trigger_to_model(self, trigger, model):
        trig_func = partial(self.events[trigger].trigger, model)
        setattr(model, trigger, trig_func)
其實這個還是給model繫結偏函式,以後我們就能這麼呼叫model.melt()。
所以到了這裡我們Machine例項關於model引數如下:
model.trigger("xxx")
model.to_liquid()
model.to_solid()
model.to_gas()
model.to_plasma()
model.melt()
model.mionize()
model.sublimate()
model.evaporate()
接著繼續在add_model()中:
    for _, state in self.states.items():
        self._add_model_to_state(state, model)
和上面差不多,遍歷呼叫_add_model_to_state(state, model)
    def _add_model_to_state(self, state, model):
        setattr(model, 'is_%s' % state.name,
                partial(self.is_state, state.name, model))
所以到了這裡我們Machine例項關於model引數如下:
model.is_solid
model.is_liquid
model.is_gas
model.is_plasms
model.state # 這個是model.setState()把初始化狀態如solid設定過來生成的屬性
好了,我們知道了model現在多了很多函式和屬性。

好的,現在我們具體來看看呼叫model.melt()到底發生了什麼呢?它其實是呼叫self.events['melt'].trigger(model),
好的,看看self.events['melt'].trigger(model)裡面是啥?
    def trigger(self, model, *args, **kwargs):
        f = partial(self._trigger, model, *args, **kwargs)
        return self.machine._process(f)
好的,原來是呼叫self.events['melt']._trigger(model),那麼這個實際處理函式_trigger()裡面又是啥呢?
        state = self.machine.get_state(model.state)
        if state.name not in self.transitions:
            msg = "%sCan't trigger event %s from state %s!" % (self.machine.name, self.name,
                                                               state.name)
            if state.ignore_invalid_triggers:
                logger.warning(msg)
                return False
            else:
                raise MachineError(msg)
第一句就先找出當前model的狀態是什麼:<State('solid')@4372239248>.
然後判斷state.name 在不在 當前event的transitions中:{'solid': [<Transition('solid', 'liquid')@4372347728>]}
好吧,確實存在,那麼就不用if語句塊啦。_trigger()繼續往下:
event_data = EventData(state, self, self.machine, model, args=args, kwargs=kwargs)
這個生成一個event_data例項,顧名思義,它就是一放資料的,裡面放了當前machine,當前state,當前event,當前的model,transitions,執行transition()的結果result,當然不僅僅是放資料而已,它還會update(),更新machine狀態。好吧,_trigger()繼續往下:
            for t in self.transitions[state.name]:
                event_data.transition = t
                if t.execute(event_data):
                    event_data.result = True
                    break
如上我們的self.transitions['solid']只有一個元素t:{'solid': [<Transition('solid', 'liquid')@4372347728>]},把這個元素t賦值給event_data後,開始執行t,等會執行結果還是要放到event_data中呢。
總結下,到這裡我們執行model.melt(),其實就是執行self.events['melt'].transitions['solid'].execute().

好的,那我們繼續看看這個t.execute(event_data)怎麼個執行法。
因為我們沒帶什麼prepare, conditions等高階引數,所以我們把這個execute()簡化成:
    def execute(self, event_data):
        self._change_state(event_data)
        return True
好吧,繼續看看transition._change_state(),顧名思義,它就是專門處理狀態的更新:
    def _change_state(self, event_data):
        event_data.machine.get_state(self.source).exit(event_data)
        event_data.machine.set_state(self.dest, event_data.model)
        event_data.update(event_data.model)
        event_data.machine.get_state(self.dest).enter(event_data)
沒什麼好說的,就是單純的處理前狀態"solid"的exit(),把當前狀態置成desc的狀態="liquid", 返回True。


總結下,Machine就是有兩個self.events={}, self.states=[]輔助圍著self.model轉,維護好這個model的狀態,即可!
這個transitions庫大量運用偏函式呀和動態生成屬性函式什麼的,不過這也正常,畢竟從demo上看來,demo越簡單,底下的操作越複雜。

以上