在Python中是否有一个漂亮的State Machine框架?

时间:2010-11-04 10:56:35

标签: python state-machine

来自Ruby世界,我们拥有漂亮的状态机框架like the one recently baked into Rails,我很惊讶在Python中找不到具有相似美感的明显候选人。我想避免自己动手;面向对象的状态机设计通常要求你每次添加一个状态时都会抛出一堆python(在这种情况下我经常这样做)。

我应该在Python代码中使用的状态机的框架是什么?在任何表现或其他考虑之前,我想要最优雅的代码。

9 个答案:

答案 0 :(得分:2)

你可以尝试这个片段

django acts_as_statemachine

答案 1 :(得分:2)

我认为工具PySCXML也需要仔细研究。该项目使用W3C定义:状态图XML(SCXML):用于控制抽象的状态机符号

SCXML提供基于CCXML和Harel状态表的基于状态机的通用执行环境

目前,SCXML是一份工作草案;但很有可能很快就会得到一个W3C推荐(这是第9稿)。

另一个有趣的要点是,有一个Apache Commons项目旨在创建和维护一个Java SCXML引擎,该引擎能够执行使用SCXML文档定义的状态机,同时抽象出环境接口......以及某些其他当SCXML离开它的草案状态时,将来会出现支持这项技术的工具......

答案 2 :(得分:2)

我正在寻找同样的东西,到目前为止xworkflow似乎是我能找到的最佳人选。

即使我是python的新手,在我看来,没有标准的库可以用于所有东西,但是社区提供了大量的独立实现,有些比其他的更加pythonic,但最终他们中的大多数都很棒。我找到的其他实现如下所示。

答案 3 :(得分:1)

我经常只使用dict来进行状态机描述。根据应用程序,键可能是(状态,事件),因此值可能是(new_state,args)。例如:

machine = {
        ('state_a', 'x'): ('state_b', 'arg1'),
        ('state_b', 'y'): ('state_c', 'arg2'),
        ...
}

读取和执行该dict的类,函数或生成器可以非常简单,具体取决于您希望转换如何工作。例如,使用python最近的.send()方法的生成器可能是编写简单事件驱动的Model-View-Controller组件的一种方法。使用回调代替状态和/或事件的字符串将不再需要大量的if / then代码。

我知道这是“滚动你自己的”,但实际上我发现所有这些都适合于几十行代码,具体取决于状态机的大小,并且可以根据应用程序进行定制以更好地适应比典型的通用框架。它通常比那些框架需要更少的设置代码。

这是一个稍微更完整的示例,使用状态的回调 - 如果您总是希望在状态条目上执行相同的代码,那么这就是您要做的事情。 (使用事件的回调将为您提供特定于转换的代码。):

def foo(x):
    print 'foo got', x
    return 'x'

def bar(x):
    print 'bar got', x
    return 'y'

def baz(x):
    print 'baz got', x
    return 'z'

machine = {
    (foo, 'x'): (bar, 'arg1'),
    (bar, 'y'): (baz, 'arg2'),
    (baz, 'z'): (foo, 'arg3'),
    }

state,arg = foo,'arg0'
while True:
    event = state(arg)
    res = machine.get((state, event))
    if not res:
        print "halting on", state, event
        break
    state,arg = res

这是输出:

foo got arg0
bar got arg1
baz got arg2
foo got arg3
bar got arg1
baz got arg2
foo got arg3
bar got arg1
baz got arg2
foo got arg3
...

答案 4 :(得分:1)

我知道这有点晚了,但只是做了一些研究并发现了这篇文章。 我在我的django-ostinato项目中编写了自己的Statemachine。

https://github.com/andrewebdev/django-ostinato/blob/master/ostinato/statemachine/core.py

此处的文档: https://django-ostinato.readthedocs.org/en/latest/ostinato.statemachine.html

编写状态机是为了不需要直接将其集成到django模型中,但是您可以使用模型实例对其进行初始化。我一直在使用它来处理几个复杂的状态机问题。

此外,状态机是框架无关的,因为您只是传递一个对象实例。您只需要确保实例具有包含实际状态的属性。

可能有更好的方法,但到目前为止,这对我有好处。

答案 5 :(得分:1)

答案 6 :(得分:0)

pyparsing示例中包含状态机Python语言扩展,它允许您导入包含状态机规范的.pystate文件,格式为:

#
# librarybookstate.pystate
#
# This state machine models the state of books in a library.
#

statemachine BookState:
    New -(shelve)-> Available
    Available -(reserve)-> OnHold
    OnHold -(release)-> Available
    Available -(checkout)-> CheckedOut
    CheckedOut -(checkin)-> Available

然后,Python代码像常规模块一样将其导入:

import statemachine
import librarybookstate


class Book(librarybookstate.BookStateMixin):
    def __init__(self):
        self.initialize_state(librarybookstate.New())

答案 7 :(得分:0)

添加一些参考文献,因为这个问题很古老,需要更新的答案。

纯python状态机:
https://github.com/pytransitions/transitions

Django支持状态机: https://github.com/viewflow/django-fsm

答案 8 :(得分:0)

我不喜欢通常使用的过度客观化模式,这更让我...

位于https://github.com/kashifrazzaqui/themstates

from themstates import StateMachine

sm = StateMachine()

# Define 'from' state -> 'event' -> 'to' state
sm.define('solid -> melt -> liquid')
sm.define('liquid -> vaporize -> gas')
sm.define('gas -> condense -> liquid')
sm.define('liquid -> freeze -> solid')

print('All states', sm.get_states()) #Lets see if we have all our states

# Generic action that we want to execute on state change
def some_action_function(event, payload):
            print(event, payload)

print('Actionable states', sm.get_actionable_states())

sm.add_action('solid', some_action_function)
sm.add_action('liquid', some_action_function)
sm.add_action('gas', some_action_function)

print('Actionable states', sm.get_actionable_states())

sm.start('liquid')

sm.handle('freeze', 'its getting cold')
print('Current State', sm.get_current_state())
sm.handle('vaporize', 'does nothing to a solid')
print('Current State', sm.get_current_state())
print('Previous state', sm.get_previous_state())
sm.handle('melt', 'its getting hot')
sm.handle('vaporize', 'cloudy now')

sm.reset()
print(sm.get_history()