状态机:Python 中的算法和编程方法(使用状态机)




  什么是 Python?
  请简要回顾本专栏中篇文章Python 是由 Guido van Rossum 开发免费高级解释型语言其语法简单易懂而其面向对象语义功能强大(但又灵活)Python 可以广泛使用并具有高度可移植性
  
  什么是状态机?
  有关状态机个极度确切描述是它是个有向图形组节点和组相应转移组成状态机通过响应系列事件而“运行”每个事件都在属于“当前”节点转移控制范围内其中范围是节点个子集返回“下个”(也许是同个)节点这些节点中至少有个必须是终态当到达终态状态机停止
  
  但个抽象数学描述(就像我刚给出)并不能真正介绍说明在什么情况下使用状态机可以解决实际编程问题种策略就是将状态机定义成种强制性编程语言其中节点也是源码行从实用角度看这个定义尽管精确但它和第种描述都是纸上谈兵、毫不实用(对于介绍说明型、型或基于约束语言例如Haskell、Scheme 或 Prolog定会发生这种情况)
  
  让我们尝试使用更适合身边实际任务例子来进行讨论逻辑上每个规则表达式都等价于个状态机而每个规则表达式语法分析器都实现这个状态机实际上大多数员编写状态机时并没有真正考虑到这
  
  在以下这个例子中我们将研究状态机真正探索性定义通常我们有些区别思路方法来响应组有限数量事件某些情况下响应只取决于事件本身但在其它情况下适当操作取决于以前事件
  
  本文中讨论状态机是高级机器其目是演示类问题编程解决方案如果有必要按响应事件行为类别来讨论编程问题那么您解决方案很可能是显式状态机
  
  文本处理状态机
  最可能显式状态机个编程问题涉及到处理文本文件处理文本文件通常包括读取信息单元(通常叫做或行)然后对刚读取单元执行适当操作某些情况下这个处理是“无状态”(即每个这样单元都包含了足够信息可以正确确定要执行什么操作)在其它情况下即使文本文件不是完全无状态数据也只有有限上下文(例如操作取决于不比行号更多信息)但是在其它常见文本处理问题中输入文件是极具“状态”块数据含义取决于它前面串(也许是它后面串)报告、大型机数据输入、可读文本、编程源文件和其它种类文本文件都是有状态个简单例子是可能出现在 Python 源文件中行代码:
  
  myObject = SomeClass(this, that, other)
  
  这行表示如果恰好有以下几行围绕着这则有部分内容区别:
  
  """How to use SomeClass:
  myObject = SomeClass(this, that, other)
  """
  我们应知道我们处于“块引用”状态以确定这行代码是部分注释而不是 Python 操作
  
  何时不使用状态机
  当开始为任何有状态文本文件编写处理器任务时问自己您希望在文件中找到什么类型输入项每种类型输入项都是种状态候选项这些类型共有几种如果数字很大或者不确定则状态机也许不是正确解决思路方法(在这种情况下某些数据库解决方案可能更适合)
  
  还请考虑您是否需要使用状态机许多情况下最好从更简单思路方法入手也许会发现即使文本文件是有状态也有种简单思路方法可以分块读取它(其中每块是种类型输入值)实际上在单状态块中仅当文本类型的间转移需要基于内容计算时才有必要实现状态机
  
  下面这个简单例子介绍说明了需要使用状态机情况请考虑用于将列数字划分成几块两个规则在第个规则中列表中零表示块的间间断第 2个规则中个块中元素总和超过 100 时会发生块的间间断由于它使用累加器变量来确定是否达到了阈值您不能“马上”看到子列表边界因此第 2个规则也许更适合于类似于状态机机制
  
  稍微有些状态、但由不太适合用状态机处理文本文件例子是 风格 .ini 文件这种文件包括节头、注释和许多赋值例如:
  
  ; the colorscheme and userlevel
  [colorscheme]
  background=red
  foreground=blue
  title=green
  
  [userlevel]
  login=2
  title=1
  
  我们例子没有实际含义但它表明了 .ini 格式些有趣特性
  
  就某种意义而言类型由它确定(可能是分号、左花括号或字母)
  
  从另种角度看这种格式是“有状态关键字 "title" 大概表示如果它出现在每节中那么就有独立内容
  
  您可以编写个有 COLORSCHEME 状态和 USERLEVEL 状态文本处理器这个仍处理每个状态赋值但这好象不是处理此问题 正确思路方法例如可以使用 Python 代码在这个文本文件中只创建自然块如:
  
  处理 .INI 文件分块 Python 代码
  
  import
  txt = open('hypothetical.ini').read
  sects = .split(txt, '[')
  for sect in sects:
   # do something with sect, like get its name
   # (the stuff up to ']') and read its assignments
  
  或者如果愿意可以使用单个 current_section 变量来确定位置:
  
  处理 .INI 文件计算 Python 代码
  
  for line in open('hypothetical.ini').readlines:
   line[0] '[':
   current_section = line(1:-2)
   el line[0] ';':
   pass # ignore comments
   :
   apply_value(current_section, line)
  
  何时使用状态机
  现在我们已经决定了如果文本文件“太简单”就不使用状态机让我们再研究 需要使用状态机情况本专栏中 最近篇文章讨论了实用 Txt2Html它将“智能 ASCII”(包括本文)转换成 HTML让我们扼要重述
  
  “智能 ASCII”是种文本格式它使用些间隔约定来区分文本块类型如头、常规文本、引语和代码样本虽然读者或作者能容易地通过查看分析这些文本块类型的间转移但却没有简单思路方法可以让计算机将“智能 ASCII”文件分割成组成它文本块不像 .ini 文件举例文本块类型可以任何顺序出现在任何情况下都没有单定界符来分隔块(空行 通常分隔文本块但代码样本中空行却不定结束代码样本并且文本块不需要用空行来分隔)由于需要以区别方式重新格式化每个文本块以生成正确 HTML 输出状态机似乎就是自然解决方案
  
  Txt2Html 阅读器般功能如下:
  
  在状态中启动
  读取行输入
  根据输入和当前状态转移到新状态或按适合当前状态方式处理该行
  
  这个例子是有关您会遇到最简单情况但它介绍说明了我们描述过以下模式:
  
  Python 中个简单状态机输入循环
  
  global state, blocks, bl_num, block
  #-- Initialize the globals
  state = "HEADER"
  blocks = [""]
  bl_num = 0
  block = 1
  for line in fhin.readlines:
   state "HEADER": # blank line means block of header
   blankln.match(line): block = 1
   el textln.match(line): startText(line)
   el codeln.match(line): startCode(line)
   :
   block: startHead(line)
   : blocks[bl_num] = blocks[bl_num] + line
   el state "TEXT": # blank line means block of text
   blankln.match(line): block = 1
   el headln.match(line): startHead(line)
   el codeln.match(line): startCode(line)
   :
   block: startText(line)
   : blocks[bl_num] = blocks[bl_num] + line
   el state "CODE": # blank line does not change state
   blankln.match(line): blocks[bl_num] = blocks[bl_num] + line
   el headln.match(line): startHead(line)
   el textln.match(line): startText(line)
   : blocks[bl_num] = blocks[bl_num] + line
   :
   raise ValueError, "unexpected input block state: "+state
  
  可以用 Txt2Html 从中取出该代码源文件(请参阅参考资料)请注意:变量 state 声明为 global(如 startText)中更改它转移条件如 textln.match是规则表达式模式但它们可能也是定制实际上以后会在中执行格式化状态机只将文本文件分析成 blocks 列表中带标签
  
  抽象状态机类
  在表单和中使用 Python 实现抽象状态机很容易这使状态机模型比前个例子中简单条件块显得更突出(初看其中条件和其它条件没有什么区别)而且以下类及其关联处理在隔离状态中操作方面完成得很好许多情况下这改善了封装和可读性
  
  文件:statemachine.py
  
  from import upper
   StateMachine:
   def __init__(self):
   self.handlers = {}
   self.startState = None
   self.endStates =
   def add_state(self, name, handler
Tags:  vhdl状态机 什么是状态机 有限状态机 状态机

延伸阅读

最新评论

发表评论