Python的Transitions库实现有限状态机(FSM)

有限状态机(Finite-state machine, FSM),又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。FSM是一种算法思想,简单而言,有限状态机由一组状态、一个初始状态、输入和根据输入及现有状态转换为下一个状态的转换函数组成。现实世界中存在大量具有有限个状态的系统:钟表系统、电梯系统、交通信号灯系统、通信协议系统、正则表达式、硬件电路系统设计、软件工程,编译器等,有限状态机的概念就是来自于现实世界中的这些有限系统。

transitions是一个由Python实现的轻量级的、面向对象的有限状态机框架。

transitions最基本的用法如下:

  1. 先自定义一个类Matter
  2. 定义一系列状态和状态转移(定义状态和状态转移有多种方式,官网上给了最快速理解的一个例子)
  3. 初始化状态机
    4.获取当前的状态或者进行转化
from transitions import Machine

class Matter(object):
    pass

model = Matter()

#The states argument defines the name of states
states=['solid', 'liquid', 'gas', 'plasma']

# The trigger argument defines the name of the new triggering method
transitions = [
    {'trigger': 'melt', 'source': 'solid', 'dest': 'liquid' },
    {'trigger': 'evaporate', 'source': 'liquid', 'dest': 'gas'},
    {'trigger': 'sublimate', 'source': 'solid', 'dest': 'gas'},
    {'trigger': 'ionize', 'source': 'gas', 'dest': 'plasma'}]

machine = Machine(model=model, states=states, transitions=transitions, initial='solid')

# Test
print(model.state)    # solid
model.melt()
print(model.state)   # liquid
model.evaporate()
print(model.state)

上面那个例子是物体的几个状态的转换,如下图:


状态变化图.png

当然transitions库还有更高阶一点的用法,比如直接显示出图形,官网上是说可以用pygraphviz 来显示,但是本身pygraphviz 在windows上有一些问题,所以没有试验成功,等以下问题修复后准备再次尝试。
https://github.com/pytransitions/transitions/issues/258

可能有的同学好奇这个transitions库对于我们测试有什么帮助呢?
大家还记得测试设计方法中有一种称之为 状态迁移法 么?其实在设计测试用例的时候,需要在各种状态之间迁移并且最好能够做到随机的处理。

这部分状态迁移的测试用例在自动化的时候,Transitions库能在这方面对我们有一定的帮助。

from transitions import Machine

class AModel(object):
    def __init__(self):
        self.sv = 0  # state variable of the model
        self.conditions = {  # each state
            'sA': 0,
            'sB': 3,
            'sC': 6,
            'sD': 0,
        }

    def poll(self):
        if self.sv >= self.conditions[self.state]:
            self.next_state()  # go to next state
        else:
            getattr(self, 'to_%s' % self.state)()  # enter current state again

    def on_enter(self):
        print('entered state %s' % self.state)

    def on_exit(self):
        print('exited state %s' % self.state)


# setup model and state machine
model = AModel()

# init transitions model
list_of_states = ['sA', 'sB', 'sC', 'sD']
machine = Machine(model=model, states=list_of_states, initial='sA',
                  ordered_transitions=True, before_state_change='on_exit',
                  after_state_change='on_enter')

# begin main
for i in range(0, 10):
    print('iter is: ' + str(i) + " -model state is:" +  model.state)
    model.sv = i
    model.poll()

上面这段代码执行的时候的效果如下:

iter is: 0 -model state is:sA
exited state sA
entered state sB
iter is: 1 -model state is:sB
exited state sB
entered state sB
iter is: 2 -model state is:sB
exited state sB
entered state sB
iter is: 3 -model state is:sB
exited state sB
entered state sC
iter is: 4 -model state is:sC
exited state sC
entered state sC
iter is: 5 -model state is:sC
exited state sC
entered state sC
iter is: 6 -model state is:sC
exited state sC
entered state sD
iter is: 7 -model state is:sD
exited state sD
entered state sA
iter is: 8 -model state is:sA
exited state sA
entered state sB
iter is: 9 -model state is:sB
exited state sB
entered state sC

Transitions库的具体用法可以参照它的github项目(https://github.com/pytransitions/transitions),还有一些extensions也很有效的,这部分有时间以后会继续研究。

推荐阅读更多精彩内容