https://blog.csdn.net/lly1122334/article/details/124127799
https://github.com/pytransitions/transitions?tab=readme-ov-file#automatic-transitions-for-all-states
- 初试
from transitions import Machine
class Matter:
states = ['solid', 'liquid', 'gas', 'plasma'] # 状态有固态、液态、气态、等离子态
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'}
]
def __init__(self):
"""不定型物体
固态→熔化→液态
液态→蒸发→气态
固态→升华→气态
气态→电离→等离子态
"""
self.machine = Machine(model=self, states=Matter.states, transitions=Matter.transitions, initial='solid')
lump = Matter()
print(lump.state) # solid
lump.melt()
print(lump.state) # liquid
- 绘图1
from transitions.extensions import GraphMachine
class Matter:
pass
states = ['solid', 'liquid', 'gas', 'plasma']
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 = GraphMachine(Matter(), states=states, transitions=transitions, initial='solid')
# machine = GraphMachine(lump, states=states, transitions=transitions, initial='solid', show_auto_transitions=True) # 完整流程
machine.get_graph().draw('result.jpg', prog='dot')
- 绘图2
from transitions import Machine
from transitions.extensions import GraphMachine
def draw_machine(machine, filename='result.png'):
"""绘制有限状态机"""
transitions = []
for trigger, event in machine.events.items():
for source, _transitions in event.transitions.items():
for i in _transitions:
transitions.append({'trigger': trigger, 'source': source, 'dest': i.dest})
machine = GraphMachine(model=machine.model, states=list(machine.states.keys()), transitions=transitions,
initial=machine.initial)
graph = machine.get_graph()
graph.edge_attr['fontname'] = 'Microsoft Yahei'
graph.node_attr['fontname'] = 'Microsoft Yahei'
graph.graph_attr['fontname'] = 'Microsoft Yahei'
graph.graph_attr['dpi'] = '300' # 设置分辨率
graph.graph_attr.pop('label') # 删除标题
graph.draw(filename, prog='dot')
class Matter:
pass
states = ['solid', 'liquid', 'gas', 'plasma']
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(Matter(), states=states, transitions=transitions, initial='solid', auto_transitions=False)
draw_machine(machine)
- 状态及检查懒方法修改前缀.py
from transitions import Machine
class Matter:
def __init__(self):
self.machine = Machine(model=self, states=['solid', 'liquid', 'gas'], initial='solid',
model_attribute='matter_state')
lump = Matter()
print(lump.matter_state) # solid
print(lump.is_matter_state_solid()) # True
print(lump.to_matter_state_gas()) # True
- 枚举
from enum import Enum
from transitions import Machine
class States(Enum):
ERROR = 0
RED = 1
YELLOW = 2
GREEN = 3
transitions = [
['proceed', States.RED, States.YELLOW],
['proceed', States.YELLOW, States.GREEN],
['error', '*', States.ERROR]
]
m = Machine(states=States, transitions=transitions, initial=States.RED)
assert m.is_RED()
assert m.state is States.RED
state = m.get_state(States.RED)
print(state.name) # RED
m.proceed()
m.proceed()
assert m.is_GREEN()
m.error()
assert m.state is States.ERROR
6. 转换状态
from transitions import Machine
class Matter:
pass
states = ['solid', 'liquid', 'gas', 'plasma']
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'}
]
lump = Matter()
machine = Machine(model=lump, states=states, transitions=transitions, initial='solid')
print(lump.state) # 初始化状态为固态solid
print(machine.get_triggers('solid')) # 获取固态的触发器(转换状态的函数)
lump.to_plasma() # 尝试转换为等离子态
print(lump.state) # 竟然成功了,实际上不能直接转换为等离子态
print()
lump = Matter()
machine = Machine(model=lump, states=states, transitions=transitions, initial='solid', auto_transitions=False) # 禁止自动转换
print(lump.state) # 初始化状态为固态solid
print(machine.get_triggers('solid')) # 获取固态的触发器(转换状态的函数)
try:
lump.to_plasma() # 尝试转换为等离子态失败
print(lump.state)
except Exception as e:
print(e)
- 获取触发器(转换状态的函数)
from transitions import Machine
class Matter:
pass
lump = Matter()
states = ['solid', 'liquid', 'gas', 'plasma']
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=lump, states=states, transitions=transitions, ignore_invalid_triggers=True,
auto_transitions=False) # 禁止自动转换
print(machine.get_triggers('solid'))
print(machine.get_triggers('liquid'))
print(machine.get_triggers('plasma'))
print(machine.get_triggers('solid', 'liquid', 'gas', 'plasma')) # 一次获取多个
# ['melt', 'sublimate']
# ['evaporate']
# []
# ['melt', 'evaporate', 'sublimate', 'ionize']
- 获取转换逻辑.py
from transitions import Machine
def get_transitions(machine, auto_transitions=False):
"""获取转换逻辑"""
transitions = []
for trigger, event in machine.events.items():
if auto_transitions == False and trigger.startswith('to_'):
continue
for source, _transitions in event.transitions.items():
for i in _transitions:
transitions.append({'trigger': trigger, 'source': source, 'dest': i.dest})
return transitions
class Matter:
pass
lump = Matter()
states = ['solid', 'liquid', 'gas', 'plasma']
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=lump, states=states, transitions=transitions)
print(get_transitions(machine))
# [{'trigger': 'melt', 'source': 'solid', 'dest': 'liquid'}, {'trigger': 'evaporate', 'source': 'liquid', 'dest': 'gas'}, {'trigger': 'sublimate', 'source': 'solid', 'dest': 'gas'}, {'trigger': 'ionize', 'source': 'gas', 'dest': 'plasma'}]
- 批量添加状态转换
from transitions import Machine
class Matter:
pass
lump = Matter()
states = ['solid', 'liquid', 'gas', 'plasma']
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=lump, states=states, transitions=transitions, auto_transitions=False) # 禁止自动转换
machine.add_transition('transmogrify', ['solid', 'liquid', 'gas'], 'plasma') # 批量添加
machine.add_transition('to_liquid', '*', 'liquid') # 批量添加
print(machine.get_triggers('solid'))
print(machine.get_triggers('liquid'))
print(machine.get_triggers('gas'))
print(machine.get_triggers('plasma'))
# ['melt', 'sublimate', 'transmogrify', 'to_liquid']
# ['evaporate', 'transmogrify', 'to_liquid']
# ['ionize', 'transmogrify', 'to_liquid']
# ['to_liquid']
- 自反转换
from transitions import Machine
class Matter:
pass
def change_shape():
print(1)
lump = Matter()
states = ['solid', 'liquid', 'gas', 'plasma']
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=lump, states=states, transitions=transitions, initial='solid', auto_transitions=False) # 禁止自动转换
machine.add_transition('touch', ['liquid', 'gas', 'plasma'], '=', after=change_shape) # 自反转换,并在转换后调用某函数
print(machine.get_triggers('solid'))
print(machine.get_triggers('liquid'))
print(machine.get_triggers('gas'))
print(machine.get_triggers('plasma'))
print()
# ['melt', 'sublimate']
# ['evaporate', 'touch']
# ['ionize', 'touch']
# ['touch']
print(lump.state)
lump.melt()
print(lump.state)
lump.touch()
print(lump.state)
# solid
# liquid
# 1
# liquid
- 内部转换
from transitions import Machine
class Matter:
pass
def change_shape():
print(1)
lump = Matter()
states = ['solid', 'liquid', 'gas', 'plasma']
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=lump, states=states, transitions=transitions, initial='solid', auto_transitions=False) # 禁止自动转换
machine.add_transition('internal', ['liquid', 'gas'], None, after=change_shape) # 自反转换,并在转换后调用某函数
print(machine.get_triggers('solid'))
print(machine.get_triggers('liquid'))
print(machine.get_triggers('gas'))
print(machine.get_triggers('plasma'))
print()
# ['melt', 'sublimate']
# ['evaporate', 'internal']
# ['ionize', 'internal']
# []
print(lump.state)
lump.melt()
print(lump.state)
lump.internal()
print(lump.state)
# solid
# liquid
# 1
# liquid
- 顺序转换
import random
from transitions import Machine
class Matter:
pass
def check():
success = random.randint(0, 1)
if success:
print('转换状态')
else:
print('不转换状态')
return success
def f1():
return check()
def f2():
return check()
def f3():
return check()
states = ['A', 'B', 'C']
machine = Machine(states=states, initial=states[0])
machine.add_ordered_transitions()
# machine.add_ordered_transitions(['A', 'C', 'B']) # 指定顺序
# machine.add_ordered_transitions(conditions=check) # 为进行转换必须通过的条件,True则转换状态
# machine.add_ordered_transitions(conditions=[f1, f2, f3]) # 同上,列表里的个数与states同,一一对应
# machine.add_ordered_transitions(loop=False) # 禁止循环
for _ in range(4): # 转换四次
print(machine.state)
machine.next_state()
# A
# B
# C
# A
- 队列转换.py
import random
from transitions import Machine
class Matter:
pass
def go_to_C():
global machine
machine.to_C()
def after_advance():
print('I am in state B now!')
def entering_C():
print('I am in state C now!')
states = ['A', 'B', 'C']
machine = Machine(states=states, initial=states[0])
machine.add_transition('advance', 'A', 'B', after=after_advance)
print(machine.state) # A
machine.on_enter_B(go_to_C) # 转换为B时调用go_to_C
machine.on_enter_C(entering_C) # 转换为C时调用entering_C
machine.advance()
print(machine.state) # C
- 满足条件才转换状态
from transitions import Machine
class Matter:
def is_flammable(self):
"""是否易燃物"""
return False
def is_really_hot(self):
"""高温"""
return True
lump = Matter()
states = ['solid', 'liquid', 'gas', 'plasma']
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=lump, states=states, transitions=transitions, initial='solid', auto_transitions=False) # 禁止自动转换
machine.add_transition('heat', 'solid', 'gas', conditions='is_flammable') # 加热时如果是易燃物会变气态
# machine.add_transition('heat', 'solid', 'gas', unless=['is_flammable', 'is_really_hot']) # 加热时不易燃且不高温变气态
machine.add_transition('heat', 'solid', 'liquid', conditions=['is_really_hot']) # 加热时如果高温会变液态
print(lump.state)
lump.heat()
print(lump.state)
# solid
# liquid
- 转换状态前后回调
from transitions import Machine
class Matter:
def make_hissing_noises(self):
print("HISSSSSSSSSSSSSSSS")
def disappear(self):
print("where'd all the liquid go?")
lump = Matter()
states = ['solid', 'liquid', 'gas', 'plasma']
transitions = [
{'trigger': 'melt', 'source': 'solid', 'dest': 'liquid', 'before': 'make_hissing_noises'},
{'trigger': 'evaporate', 'source': 'liquid', 'dest': 'gas', 'after': 'disappear'}
]
machine = Machine(model=lump, states=states, transitions=transitions, initial='solid')
print(lump.state)
lump.melt()
print(lump.state)
lump.evaporate()
print(lump.state)
# solid
# HISSSSSSSSSSSSSSSS
# liquid
# where'd all the liquid go?
# gas
######################################################
import random
from transitions import Machine
class Matter:
heat = False # 是否沸腾
attempts = 0 # 尝试次数
def heat_up(self):
"""随机沸腾"""
self.heat = random.random() < 0.25
def count_attempts(self):
self.attempts += 1
def stats(self):
print('It took you %i attempts to melt the lump!' % self.attempts)
@property
def is_really_hot(self):
return self.heat
lump = Matter()
states = ['solid', 'liquid', 'gas', 'plasma']
transitions = [
{'trigger': 'melt', 'source': 'solid', 'dest': 'liquid', 'prepare': ['heat_up', 'count_attempts'], 'conditions': 'is_really_hot', 'after': 'stats'},
]
machine = Machine(model=lump, states=states, transitions=transitions, initial='solid')
print(lump.state)
lump.melt()
lump.melt()
lump.melt()
lump.melt()
print(lump.state)
# solid
# It took you 4 attempts to melt the lump!
# liquid
- 状态机转换状态前后回调
from transitions import Machine
class Matter:
def before(self):
print('before')
def after(self):
print('after')
def prepare(self):
print('prepare')
def before_state_change(self):
print('before_state_change')
def after_state_change(self):
print('after_state_change')
lump = Matter()
states = ['solid', 'liquid', 'gas', 'plasma']
transitions = [
{'trigger': 'melt', 'source': 'solid', 'dest': 'liquid',
'before': 'before', 'after': 'after', 'prepare': 'prepare'},
]
machine = Machine(model=lump, states=states, transitions=transitions, initial='solid',
before_state_change='before_state_change', after_state_change='after_state_change')
lump.melt()
# prepare
# before_state_change
# before
# after
# after_state_change
- 异常处理
from transitions import Machine
class Matter:
def raise_error(self, event):
raise ValueError('Oh no')
def prepare(self, event):
print('I am ready!')
def finalize(self, event):
print('Result: ', type(event.error), event.error)
lump = Matter()
states = ['solid', 'liquid', 'gas', 'plasma']
machine = Machine(model=lump, states=states, prepare_event='prepare', before_state_change='raise_error',
finalize_event='finalize', send_event=True)
try:
lump.to_gas()
except ValueError:
pass
print(lump.state)
# I am ready!
# Result: <class 'ValueError'> Oh no
# initial
##################################################################
from transitions import Machine
class Matter(object):
def raise_error(self, event):
raise ValueError('Oh no')
def handle_error(self, event):
print('Fixing things ...')
del event.error # 看不到就不会发生
states = ['solid', 'liquid', 'gas', 'plasma']
lump = Matter()
m = Machine(lump, states, before_state_change='raise_error', on_exception='handle_error', send_event=True)
try:
lump.to_gas()
except ValueError:
pass
print(lump.state)
# Fixing things ...
# initial
- 传递参数
from transitions import Machine
class Matter:
def __init__(self):
self.set_environment()
def set_environment(self, temp=0, pressure=101.325):
self.temp = temp
self.pressure = pressure
def print_temperature(self):
print(f'Current temperature is {self.temp} degrees celsius.')
def print_pressure(self):
print(f'Current pressure is {self.pressure:.2f} kPa.')
lump = Matter()
machine = Machine(model=lump, states=['solid', 'liquid'], initial='solid')
machine.add_transition(trigger='melt', source='solid', dest='liquid', before='set_environment')
lump.melt(45) # 相当于调用lump.trigger('melt', 45)
lump.print_temperature()
# Current temperature is 45 degrees celsius.
machine.set_state('solid')
lump.melt(pressure=300.23)
lump.print_pressure()
# Current pressure is 300.23 kPa.
from transitions import Machine
class Matter:
def __init__(self):
self.temp = 0
self.pressure = 101.325
def set_environment(self, event):
self.temp = event.kwargs.get('temp', 0)
self.pressure = event.kwargs.get('pressure', 101.325)
def print_temperature(self):
print(f'Current temperature is {self.temp} degrees celsius.')
def print_pressure(self):
print(f'Current pressure is {self.pressure:.2f} kPa.')
lump = Matter()
machine = Machine(model=lump, states=['solid', 'liquid'], initial='solid', send_event=True)
machine.add_transition(trigger='melt', source='solid', dest='liquid', before='set_environment')
lump.melt(temp=45)
lump.print_temperature()
# Current temperature is 45 degrees celsius.
machine.set_state('solid')
lump.melt(pressure=300.23)
lump.print_pressure()
# Current pressure is 300.23 kPa.
- 日志
import logging
from transitions import Machine
class Matter:
pass
logging.basicConfig(level=logging.DEBUG)
logging.getLogger('transitions').setLevel(logging.INFO)
lump = Matter()
states = ['solid', 'liquid', 'gas', 'plasma']
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=lump, states=states, transitions=transitions, initial='solid')
print(lump.state)
lump.melt()
print(lump.state)
# solid
# liquid
# INFO:transitions.core:Finished processing state solid exit callbacks.
# INFO:transitions.core:Finished processing state liquid enter callbacks.
执行顺序 prepare -> before->exit->enter->after