python 状态机 可视化,用Python构建一个简单的状态机。

Originally posted on my personal blog.

I discovered State Machines about 2 years ago, it was used in a solution to a problem where we were mapping the possible states of a VoIP phone call (incoming, ringing, answered, etc.) to something that we could monitor. I was amazed at how simple this was and decided to adopt state machines in my own projects.

I’m sure everyone knows what happens when you discover some new software principle; you decide that literally everything you’ve ever built needs it. However, as responsible developers, we must ask ourselves whether what we're trying to do is the best solution. We must ask what our use case is and, in this case, whether we even need a state machine. Perhaps the example below will help provide insight into what state machines can be used for.

STATE MACHINES

Before we get into implementing a simple state machine in Python lets quickly go over what a state machine is and what it looks like. In short, it’s basically a set of states and a set of actions/events, we start at one state and like a graph data structure, we can traverse through the nodes based on the condition described by the corresponding edge. We use that condition to get to the node (aka state) we’d like to. Since there is only a single state active at a time, we have a lot of control in terms of where we are within the lifecycle of the state machine. There’s a more thorough CS theory backed explanation that can be found by means of a video here. I highly recommend checking it out if you’d like to know more!

USE CASES

There are many use cases for state machines, some of which include — managing states (like call states, WiFi connectivity, and even the Android activity life cycle) or reporting metrics — duration of time for a user to complete a login (login -> pending -> success) for example.

State machines are especially interesting because, among other things, they provide well-defined scenarios and list out the conditions to get to them. This makes it very easy to scope out edge cases and how to handle them, as we are forced to consider every possible scenario our code must fall within.

Personally, the best way to understand state machines is through an everyday example.

Imagine you are looking at your password protected phone, at a high-level it has two states of operation. The first being locked, where you have limited functionality and the second being unlocked, where you can now use the device in a greater capacity.

This is what the above state machine looks like when visualized.

542cc2e2de25366dc0d8019613ac4e0c.png

USING A STATE MACHINE

We begin by defining the states, these are defined as the nodes within the state machine. In our case, we have two states; locked & unlocked. In the example below, I've also defined a State object which will handle some utility functions for our states (which extend from this object).

# state.py

class State(object):

"""

We define a state object which provides some utility functions for the

individual states within the state machine.

"""

def __init__(self):

print 'Processing current state:', str(self)

def on_event(self, event):

"""

Handle events that are delegated to this State.

"""

pass

def __repr__(self):

"""

Leverages the __str__ method to describe the State.

"""

return self.__str__()

def __str__(self):

"""

Returns the name of the State.

"""

return self.__class__.__name__

The states can then be defined as follows.

# my_states.py

from state import State

# Start of our states

class LockedState(State):

"""

The state which indicates that there are limited device capabilities.

"""

def on_event(self, event):

if event == 'pin_entered':

return UnlockedState()

return self

class UnlockedState(State):

"""

The state which indicates that there are no limitations on device

capabilities.

"""

def on_event(self, event):

if event == 'device_locked':

return LockedState()

return self

# End of our states.

Then we define the actual state machine. It's fairly simple and looks like this:

# simple_device.py

from my_states import LockedState

class SimpleDevice(object):

"""

A simple state machine that mimics the functionality of a device from a

high level.

"""

def __init__(self):

""" Initialize the components. """

# Start with a default state.

self.state = LockedState()

def on_event(self, event):

"""

This is the bread and butter of the state machine. Incoming events are

delegated to the given states which then handle the event. The result is

then assigned as the new state.

"""

# The next state will be the result of the on_event function.

self.state = self.state.on_event(event)

Fairly simple right? What this state machine does is defines a starting state LockedState and exposes a function to handle events. This function basically assigns the current state to the result of that same state when it handles the event.

Finally, we can test that implementation of the state machine using the python shell.

$ python

Python 2.7.13 (default, Apr 4 2017, 08:47:57)

[GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.38)] on darwin

Type "help", "copyright", "credits" or "license" for more information.

>>>

>>> from simple_device import SimpleDevice

>>> device = SimpleDevice()

Processing current state: LockedState

>>>

>>> device.on_event('device_locked')

>>> device.on_event('pin_entered')

Processing current state: UnlockedState

>>>

>>> device.state

UnlockedState

>>>

>>> device.on_event('device_locked')

Processing current state: LockedState

>>>

>>> device.state

LockedState

>>> device.on_event('device_locked')

You’ll notice that duplicate events are ignored and only the events that provide transitions are made use of. This becomes a very powerful tool when we want to ignore events or reduce a series of verbose events into a simpler set of events. My favorite thing is that if in the future we'd like to add more states and transitions, it's very simple to do so without rewriting a huge chunk of our codebase.

CONCLUSION

State machines are awesome, from cases that require simple state management, to metric reporting, they have proven to be very useful and extensible. The above technique was a product of implementing a state machine to handle SIP signaling events (for VoIP) and measure deltas between incoming events (to gain a better understanding of our pain points). It can definitely scale to a few dozen states and makes for a simple and easy state measurement.

If you are looking for a different solution, check out the Python transitions library which is a state machine library that looks fairly promising.

REFERENCES

While researching state machine libraries for Python I came across a page that documented a simple implementation, the above solution based on the example provided. Check out the original implementation here.

Let me know if you spot any errors, or if you just want to say hi!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python 风机故障数据样本通常是指一组包含风机故障信息的数据样本。这些样本通常包括以下信息: 1. 故障类型:样本中会明确标注故障的类型,例如电气故障、机械故障等。 2. 时间戳:每个样本都会包含一个时间戳,用于记录故障发生的时间。 3. 传感器数据:风机通常配备多个传感器来实时监测运行状态。故障样本会包含这些传感器在故障发生时的数据,例如转速、温度、振动等。 4. 外部环境数据:样本中还可能包含外部环境数据,如天气状况、风速、湿度等信息,这些数据有助于对故障发生的原因进行分析。 5. 维修记录:样本中可能还包含过往的维修记录,用于分析风机故障的频率和维修效果。 Python 可以通过使用 pandas 或 numpy等库来加载和分析这些风机故障数据样本。通过将数据导入到 pandas 的数据框中,我们可以方便地处理和分析这些数据。 对于这些故障数据样本的分析,我们可以使用数据可视化技术如绘制时间序列图、散点图,以便更好地理解风机的运行状况和故障模式。另外,我们还可以使用机器学习和深度学习算法对数据进行模型训练,以预测风机故障的可能性和提前采取相应措施,从而提高风机的可靠性和性能。 总而言之,Python 风机故障数据样本是一组记录风机故障信息的数据样本,通过使用 Python 和相应的数据分析工具,我们可以对这些样本进行分析,并对风机故障进行预测和预防。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值