跳转到主要内容

基于堆栈的有限状态机

项目描述

欢迎使用基于堆栈的有限状态机

此项目提供了一个基于堆栈的有限状态机。

状态机有一个堆栈。状态被推入和弹出堆栈。当状态被“推入”和“弹出”时,状态机将调用状态的“进入”和“退出”方法。然后,状态将根据各自的实现将其他状态推入和弹出。状态可以访问堆栈,还可以访问包含“全局”变量的上下文对象。

还提供了一些基本的状态类,可以使用这些类定义“程序”。程序定义了一组嵌套的状态类型,状态将从这些类型中构建。

安装

$ pip install stackbased-fsm

入门指南

我们可以使用Context类来定义示例上下文对象。

from stackbased_fsm import Context

class ExampleContext(Context):
    def __init__(self):
        self.a = 1
        self.b = "2"
        self.c = []


context = ExampleContext()

我们可以使用StateMachine类来构建使用上下文对象的状态机对象。

from stackbased_fsm import StateMachine

sm = StateMachine(context=context)

状态机有一个状态的堆栈。状态机堆栈上的所有状态都将访问上下文对象。上下文对象的属性类似于状态机的状态的“全局”变量。

我们可以使用State类来定义状态机中状态的类型。这是一个泛型类,它有一个类型变量,预期为上下文类。

from stackbased_fsm import State

class ExampleState(State[ExampleContext]):
    pass

我们可以使用ExampleState作为基类来定义IncrementAAssignBAppendC,分别用于增加a、分配给b和追加到c

class IncrementA(ExampleState):
    def enter(self) -> None:
        self.context.a += 1
        self.pop()


class AssignB(ExampleState):
    def enter(self) -> None:
        self.context.b = "def"
        self.pop()


class AppendC(ExampleState):
    def enter(self) -> None:
        self.context.c.append("xyz")
        self.pop()

状态机有一个run()方法,客户端可以使用它将“程序”传递给状态机。程序是一种类型构造,在最简单的情况下是一个单一的状态类,通常是一个嵌套的索引泛型状态类集(见下文)。

sm.run(IncrementA)

assert context.a == 2

我们可以使用 SequenceOfStates 类来定义一个状态序列。它是一个可变参数泛型状态类,因此可以接受任何数量的状态类作为其类型参数。

from stackbased_fsm import SequenceOfStates

ExampleSequence = SequenceOfStates[IncrementA, AssignB, AppendC]

我们可以运行序列并检查上下文是否已更新。

sm.run(ExampleSequence)

assert context.a == 3
assert context.b == "def"
assert context.c == ["xyz"]

状态机对象具有在栈上 push()pop()poppush() 状态的方法。状态对象有四个方法,分别是 enter()exit()suspend()resume()

当使用 run() 方法将程序传递给状态机时,将根据程序的根类型(一种状态类型)构造一个状态对象。然后,该状态对象被推入栈中,并调用其 enter() 方法。状态机随后遍历栈,检测状态何时被推入和弹出,相应地调用栈上状态的方法,直到栈为空。

当一个状态被推入栈后,将调用该状态的 enter() 方法。当一个状态从栈中弹出后,将调用该状态的 exit() 方法。当一个状态被另一个状态推到顶部时,将调用其 suspend() 方法,在该状态被弹出后,将调用其 resume() 方法。

例如,SequenceOfStates 的工作方式如下。当它被推入栈时,将调用其 enter() 方法。其 enter() 方法会将序列中的第一个项目推入栈。然后调用其 suspend() 方法,接着调用序列中第一个项目的 enter() 方法。如果推入的状态既不推入也不弹出另一个状态,它将被自动弹出,并调用其 exit() 方法。当该状态被弹出时,将调用序列的 resume() 方法,这将推入序列中的下一个项目。当所有项目都推入栈中后,序列的 resume() 方法将调用 pop(),这将导致它自己从栈中弹出。这可能会导致栈为空,以及程序的结束。

条件和有条件状态

“条件”状态类 ConditionState 可以用来定义条件。当调用条件状态的 enter() 方法时,将调用其 condition() 方法。在 ConditionState 类上,该方法声明为抽象,并预期在子类中实现。此方法预期返回一个布尔值(truefalse)。此值将被条件状态的 enter() 方法用于调用栈下方的状态的 set_condition_result() 方法,该状态预期为“有条件”状态,因此具有此方法。

在下面的示例中,类 AIsLessThan5condition() 方法在 a 小于 5 时返回 True

from stackbased_fsm import ConditionState


class AIsLessThan5(ConditionState):
    def condition(self):
        return self.context.a < 5

条件由有条件状态使用。例如,类 RepeatUntilRepeatWhile 是有条件状态。这些有条件状态接受两个类型变量。第一个类型变量预期是条件类型。第二个类型变量预期是状态类型。这些有条件状态在推入条件状态和推入其他状态之间交替。 RepeatUntil 以这种方式继续,直到条件为 trueRepeatWhile 以这种方式继续,直到条件为 false

在下面的示例中,ExampleLoop 将在 a 小于 5 的条件下不断推入 IncrementA

from stackbased_fsm import RepeatWhile

ExampleLoop = RepeatWhile[AIsLessThan5, IncrementA]

sm.run(ExampleLoop)

结果是 a 的值是 5。

assert context.a == 5, context.a

条件可以用 AnyConditionAllConditions(分别别名为 OrAnd)分组。

开发者

安装 Poetry

首先,请检查你是否已安装 Poetry。

$ poetry --version

如果你没有安装,请 安装 Poetry

这将有助于确保Poetry的bin目录位于您的PATH环境变量中。

但无论如何,请确保您知道poetry可执行文件的路径。Poetry安装程序会告诉您安装位置以及如何配置您的shell。

有关使用Poetry的指导,请参阅Poetry文档

PyCharm用户设置

您可以使用PyCharm轻松获取项目文件(菜单“Git > Clone...”)。然后PyCharm通常会提示您打开项目。

在新窗口中打开项目。然后PyCharm通常会提示您创建一个新的虚拟环境。

为项目创建一个新的Poetry虚拟环境。如果PyCharm尚未知道您的poetry可执行文件的位置,请在“新建Poetry环境”表单的“Poetry可执行文件”输入字段中设置您的poetry可执行文件路径。在“新建Poetry环境”表单中,您还可以选择虚拟环境将使用的Python可执行文件。

PyCharm将使用特定的Python版本为您的项目创建一个新的Poetry虚拟环境,并将根据pyproject.toml文件或项目中存在的poetry.lock文件,安装项目依赖包到这个虚拟环境中。

您可以为不同的Python版本添加不同的Poetry环境,并使用PyCharm的“Python解释器”设置在它们之间切换。如果您想使用未安装的Python版本,请使用您喜欢的包管理器,或者从Python网站下载Python安装程序。

项目依赖安装完成后,您应该能够在PyCharm中运行测试(在tests文件夹上右键单击并选择“运行”选项)。

由于pytest与PyCharm的调试器和覆盖率工具之间存在冲突,您可能需要在测试运行器模板中添加--no-cov选项。或者,只需使用Python标准库中的unittest模块。

您还应该在PyCharm中打开一个终端窗口,并从命令行运行项目的Makefile命令(见下文)。

从命令行设置

使用Git或合适的替代品获取项目文件。

在终端应用程序中,将当前工作目录更改为项目文件根目录。在这个文件夹中应该有一个Makefile。

使用Makefile创建一个新Poetry虚拟环境,并将项目的依赖包安装到其中,使用以下命令。

$ make install-packages

也可以将项目以“可编辑模式”安装。

$ make install

请注意,如果您以这种方式创建虚拟环境,然后尝试在PyCharm中打开项目并将项目配置为使用此虚拟环境作为“现有Poetry环境”,PyCharm有时会有些问题(不知道为什么)可能会造成问题。如果您遇到这些问题,可以通过删除虚拟环境并使用PyCharm创建Poetry虚拟环境来解决这个问题(见上文)。

项目Makefile命令

您可以使用以下命令运行测试。

$ make test

您可以使用以下命令检查代码格式。

$ make lint

您可以使用以下命令重新格式化代码。

$ make fmt

测试属于./tests。待测试的代码属于./stackbased_fsm

有关开发事件源应用程序的更多信息,请参阅Python eventsourcing项目

pyproject.toml 中编辑软件包依赖项。使用以下命令更新已安装的软件包(以及 poetry.lock 文件)。

$ make update-packages

项目详情


下载文件

下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于 安装软件包 的信息。

源代码分发

stackbased-fsm-0.1.tar.gz (14.1 kB 查看哈希值)

上传时间 源代码

构建分发

stackbased_fsm-0.1-py3-none-any.whl (9.6 kB 查看哈希值)

上传时间 Python 3