The concept of a state machine and a tutorial on using the state machine under Python _python

Source: Internet
Author: User
Tags sin in python

What is a state machine?

An extremely precise description of a state machine is that it is a direction graph, consisting of a set of nodes and a set of corresponding transfer functions. The state machine "runs" by responding to a series of events. Each event is within the control of a transfer function that belongs to the current node, where the scope of the function is a subset of the nodes. The function returns the "next" (perhaps the same) node. At least one of these nodes must be a final state. The state machine stops when it reaches the final state.

But an abstract mathematical description (as I have just given) does not really explain the circumstances in which a state machine can be used to solve a real programming problem. Another strategy is to define a state machine as a mandatory programming language in which nodes are also source lines. From a practical point of view, this definition, despite its accuracy, is as theoretical and impractical as the first description. (for descriptive, functional, or constrained languages, such as Haskell, Scheme, or Prolog, this does not necessarily occur.) )

Let's try to use examples that are more appropriate to the actual tasks around us. Logically, each rule expression is equivalent to a state machine, and the parser for each rule expression implements the state machine. In fact, most programmers don't really take this into account when they write state machines.

In the following example, we will look at the real exploratory definition of the state machine. In general, we have a number of different ways to respond to a limited set of events. In some cases, the response depends only on the event itself. In other cases, however, the appropriate action depends on the previous event.

The state machines discussed in this article are advanced machines designed to demonstrate a programming solution for a class of problems. If it is necessary to discuss programming issues in response to categories of event behavior, your solution is likely to be an explicit state machine.

Text Processing state machine

One programming problem that most likely invokes an explicit state machine involves working with text files. Working with a text file typically involves reading a unit of information, usually called a character or line, and then performing the appropriate action on the cell that you just read. In some cases, this process is "stateless" (that is, each of these cells contains enough information to correctly determine what to do). In other cases, even if the text file is not completely stateless, the data has only a limited context (for example, the operation depends on more information than the line number). However, in other common text processing problems, the input file is extremely "state". The meaning of each piece of data depends on the string (perhaps the string behind it) that precedes it. Reports, mainframe data entry, readable text, programming source files, and other kinds of text files are stateful. A simple example is a line of code that may appear in the Python source file:

MyObject = SomeClass (this, which, other)

This line indicates that if there are just the following lines around the line, some of the content is different:

"" "" "How to use SomeClass:
myObject = SomeClass (this, which, other)" "


We should know that we are in a "block reference" state to determine that this line of code is part of the comment rather than the Python operation.

When not to use the state machine

When you start the task of writing a processor for any stateful text file, ask yourself what type of entry you want to find in the file. Each type of entry is a candidate for a state. There are several types of these. If the numbers are large or uncertain, the state machine may not be the correct solution. (In this case, some database solutions might be more appropriate.) )

Also, consider whether you need to use a state machine. In many cases, it's better to start with a simpler approach. It may be found that even if a text file is stateful, there is a simple way to read it in chunks (where each piece is a type of input value). In fact, in a single state block, a state machine is necessary only if the transfer between text types requires content-based computing.

The following simple example illustrates the need to use a state machine. Consider the two rules used to divide a column of numbers into pieces. In the first rule, the 0 in the list represents the discontinuity between blocks. In the second rule, gaps between blocks occur when the sum of elements in a block exceeds 100. Because it uses an accumulator variable to determine whether a threshold is reached, you cannot "immediately" see the bounds of the child list. Therefore, the second rule might be more appropriate for a mechanism similar to a state machine.

An example of a slightly state, but a text file that is not suitable for working with a state machine is a Windows-style. ini file. This file includes a section header, a comment, and many assignments. For example:

; Set the ColorScheme and Userlevel
[ColorScheme]
background=red
foreground=blue
title=green
[ Userlevel]
login=2
title=1

Our example has no real meaning, but it shows some interesting features in the. ini format.

In a sense, the type of each row is determined by its first character (possibly a semicolon, Zohua parenthesis, or letter).
From another perspective, this format is "stateful" because the keyword "title" probably means that if it appears in each section, then there is a separate content.

You can write a text processor program with a ColorScheme state and a USERLEVEL state, which still handles the assignment of each state. But it doesn't seem to be the right way to deal with this problem. For example, you can use Python code to create only natural blocks in this text file, such as:
Processing. INI File Block Python code

Import
 
   string
txt = open (
  ' Hypothetical.ini '). Read ()
sects = string.split (txt, 
  ' [')
  for
 
   sect
 
   in sects:
 
  # does something with sect, as like-get
 -its-name # (the stuff up to '] ') and read its ass Ignments

Or, if you prefer, you can use a single current_section variable to determine the location:
Processing. INI file's Computational Python code

For line in
 
   open (
  ' Hypothetical.ini '). ReadLines ():
 
  if
 
   line[0] = = 
  ' [':
 Current_section = line (1:-2)
 
  elif
 
   line[0] = = 
  ': Pass
 
  # Ignore comments

 
  
 Else
 
  :
 Apply_value (current_section, line)

When to use a state machine

Now that we've decided not to use the state machine if the text file is "too simple," Let's look at the situation where we need to use the state machine. The most recent article in this column discusses utility txt2html, which converts "smart ASCII" (including this article) to HTML. Let us recapitulate.

Smart ASCII is a text format that uses some interval conventions to differentiate the type of text blocks, such as headers, regular text, quotations, and code samples. While readers or authors can easily view the transitions between these text block types, there is no easy way for the computer to split the smart ASCII file into chunks of text that compose it. Unlike. ini file examples, text block types can appear in any order. In no case will a single delimiter be used to separate blocks (empty lines typically separate blocks of text, but empty lines in code samples do not necessarily end code samples, and text blocks do not need to be separated by blank lines). Because of the need to reformat each block of text in a different way to generate the correct HTML output, the state machine appears to be a natural solution.

The general functions of the txt2html reader are as follows:

    • Starts in the initial state.
    • Reads one line of input.
    • Moves to the new state or processes the row in a manner appropriate to the current state, depending on the input and current state.

This example is about the simplest scenario you will encounter, but it illustrates the following patterns we have described:
A simple state machine input loop in Python

Global state, blocks, Bl_num, Newblock #--Initialize the Globals state = "HEADER" blocks = [""] bl_num = 0 Newblock = 1 for line in Fhin.readlines (): If state = "HEADER": # Blank line means new block of hea
 
   Der if Blankln.match (line): Newblock = 1 elif textln.match (line): Starttext (line) elif Codeln.match (line): Startcode (line) else:if Newblock:starthead (line) Else:blocks[bl_num] = b Locks[bl_num] + line elif state = = "TEXT": # Blank line means new block of TEXT if BLANKLN Match (line): Newblock = 1 elif headln.match (line): Starthead (line) elif Codeln.match (line): Startcode (l
 
   INE) Else:if Newblock:starttext (line) else:blocks[bl_num] = Blocks[bl_num] + line Elif state = = ' CODE ': # blank line does ' if Blankln.match (line): blocks[bl_num] = bl
 
  Ocks[bl_num] + LineElif Headln.match (line): Starthead (line) elif Textln.match (line): Starttext (line) Else:blocks[bl_n

 UM] = Blocks[bl_num] + line else:raise valueerror, "unexpected input blocks state:" +state

You can use txt2html to download the source file from which the code is removed (see Resources). Note that the variable state is declared global, and its value is changed in a function such as Starttext (). Transition conditions, such as Textln.match (), are regular expression patterns, but they may also be custom functions. In fact, formatting will be performed in the program later. The state machine only analyzes text files into tagged blocks in the blocks list.

Abstract state Machine Class

It's easy to use Python to implement abstract state machines in forms and functions. This makes the state machine model of the program more prominent than the simple conditional block in the previous example (at first glance, the conditions are no different from other conditions). Also, the following classes and their associated handlers do a good job in an isolated state. In many cases, this improves encapsulation and readability.
File: statemachine.py

 from string import upper class Statemachine:def __init__ (self): Self.handlers = {} self.startstate = None self.endstates = [] def add_state (self, name, handle
 
  R, end_state=0): name = UPPER (name) Self.handlers[name] = handler if End_state:self.endStates.append (name) def set_start (self, name): self.startstate = Upper (name) def run (self, cargo): Try:han Dler = Self.handlers[self.startstate] except:raise "Initializationerror", "must call. Set_start () BEF  Ore. Run () "If not Self.endStates:raise" Initializationerror ", in least one State must is an 
 
  End_state "while 1: (newstate, cargo) = Handler (cargo) if Upper (NewState) in self.endstates: Break Else:handler = Self.handlers[upper (newstate)] 
The StateMachine class is actually what the abstract state machine needs. Because it is so simple to pass a function object in Python, this class uses very few rows to compare with similar classes in other languages.

To really use the StateMachine class, you need to create some handlers for each state you want to use. The handler must conform to the pattern. It loops through the event until it is transferred to another State, at which point the handler should pass back a byte group (which includes the new state name and any cargo required by the new state handler).

The practice of using cargo as a variable in the StateMachine class encapsulates the data that the state handler requires (the state handler does not have to call its cargo variable). The state handler uses cargo to pass the content required by the next handler, so the new handler can take over the legacy work of the previous handler. Cargo typically includes a file handle that allows the next handler to read more data after the previous handler stops. Cargo may also be a database connection, a complex class instance, or a list with several items.

Now, let's look at the test samples. In this example (as outlined in the following code example), cargo is just a number that continues to pass feedback to the iteration function. As long as Val is in a range, the next value of Val is always Math_func (val). Once the function returns a value that is out of range, the value is routed to another handler, or the state machine exits after invoking a final state handler that does nothing. The example illustrates one thing: an event does not have to be an input event. It can also be a computed event (this is very rare). The difference between the state handlers is only the use of different tags when outputting the events they handle. The function is simpler, and there is no need to use a state machine. But it is a good illustration of the concept. Code may be easier to understand than explanation!
File: statemachine_test.py

From StateMachine import StateMachine def ones_counter (val): print "ones state:", WHI 
  Le 1:if val <= 0 or val >= 30:newstate = "Out_of_range"; 
  Break Elif <= val < 30:newstate = "twenties"; 
  Break Elif <= val < 20:newstate = "TENS"; Break Else:print "@%2.1f+"% val, val = Math_func (val) print ' >> ' return (NewS 
 
   Tate, Val) def Tens_counter (val): print "Tens state:" While 1:if val <= 0 or 
  Val >= 30:newstate = "Out_of_range"; 
  Break Elif 1 <= val < 10:newstate = "ones"; 
  Break Elif <= val < 30:newstate = "twenties"; Break Else:print "#%2.1f+"% val, val = Math_func (val) print ' >> ' return (NEWST
 
   Ate, Val) def Twenties_counter (val): print "Twenties State:" While1:if Val <= 0 or val >= 30:newstate = "Out_of_range"; 
  Break Elif 1 <= val < 10:newstate = "ones"; 
  Break Elif <= val < 20:newstate = "TENS"; Break Else:print "*%2.1f+"% val, val = Math_func (val) print ' >> ' return (NEWST Ate, Val) def math_func (n): From the math import sin return abs (sin (n)) *31 if __na me__== "__main__": M = StateMachine () m.add_state ("ones", Ones_counter) m.add_state ("TENS", Tens_counter) M.A Dd_state ("twenties", Twenties_counter) m.add_state ("Out_of_range", None, end_state=1) m.set_start ("ONES") m.ru

 N (1)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.