直接上代码
from enum import Enum
from typing import Dict, List
from blinker import Signal
class StateState(Enum):
NotIn = 0
Oning = 1
Outed = 2
class BaseState:
"""state base"""
def __init__(self) -> None:
self.sg_oningStart = Signal()
self.sg_oningEnd = Signal()
self._sstate = StateState.NotIn
def destory(self):
self.sg_oningStart._cleanup_receiver()
self.sg_oningStart._cleanup_sender()
self.sg_oningEnd._cleanup_receiver()
self.sg_oningEnd._cleanup_sender()
@property
def is_ready(self) -> bool:
"""StateState.NotIn"""
return self._sstate.value == 0
@property
def is_oning(self) -> bool:
"""StateState.Oning"""
return self._sstate.value == 1
@property
def is_outed(self) -> bool:
"""StateState.Outed"""
return self._sstate.value == 2
@property
def sstate(self) -> StateState:
"""StateState \n
NotIn = 0 \n
Oning = 1 \n
Outed = 2 \n
"""
return self._sstate
def enter(self):
"""sg_oningStart send"""
assert self.is_ready
self._sstate = StateState.Oning
self.sg_oningStart.send()
def exit(self):
"""sg_oningEnd send"""
assert self.is_oning
self._sstate = StateState.Outed
self.sg_oningEnd.send()
def reset(self):
"""强制初始化"""
self._sstate = StateState.NotIn
class State(BaseState):
"""state"""
def __init__(self, name: str) -> None:
super().__init__()
self.name = name
self.order = -1
def __str__(self):
return "{ State->" + f"{self.name:<10}: {self.sstate} " + "}"
__repr__ = __str__
class BaseStateMachine:
def __init__(self, listState: List[State]) -> None:
names = []
self.nowid = -1
self.ss: Dict[int, State] = {}
k = 0
self.ss[k] = State("start")
k += 1
for s in listState:
assert isinstance(s, State)
if s.name not in names:
names.append(s.name)
assert s.order == -1
s.order = k
self.ss[k] = s
k += 1
else:
raise ValueError("name 重复")
self.ss[k] = State("end")
self.endid = k
def __getitem__(self, key: int):
return self.ss.get(key)
@property
def s_start(self):
return self.ss[0]
@property
def s_end(self):
return self.ss[self.endid]
@property
def s_now(self):
return self.ss[self.nowid]
@property
def s_next(self):
if self.nowid < self.endid:
return self.ss[self.nowid + 1]
@property
def s_back(self):
if self.nowid > 0:
return self.ss[self.nowid - 1]
def states(self):
for k, v in self.ss.items():
yield (k, v.name, v)
def _strSS(self):
return [
(" " if k != self.nowid else " -> ") + f"{k}:{str(v)}"
for k, v in self.ss.items()
]
def __str__(self):
s = "{ StateMaching:\n"
s += "\n".join(self._strSS())
s += "\n}"
return s
__repr__ = __str__
class OrderSM(BaseStateMachine):
def __init__(self, lst: List[str]) -> None:
super().__init__([State(i) for i in lst])
self.enter(0)
def Next(self):
if self.nowid < self.endid:
if self.nowid >= 0:
self.ss[self.nowid].exit()
self.nowid += 1
if self.endid >= self.nowid >= 0:
self.ss[self.nowid].enter()
def enter(self, id: int):
if self.endid >= id:
while id > self.nowid:
self.Next()
else:
raise ValueError(f"id 过大 ,id:{id},self.nowid:{self.nowid}")
def __str__(self):
s = "{ OrderSM:\n"
s += "\n".join(self._strSS())
s += "\n}"
return s
__repr__ = __str__
class RandomSM(BaseStateMachine):
def __init__(self, lst: List[str]) -> None:
super().__init__([State(i) for i in lst])
self.enter(0)
def enter(self, id: int, is_reEnter: bool = False):
if self.endid >= id >= 0:
if self.nowid != id:
if self.nowid >= 0:
self.ss[self.nowid].exit()
self.ss[self.nowid].reset()
self.nowid = id
self.ss[self.nowid].enter()
else:
if is_reEnter:
self.reEnter()
else:
raise ValueError(f"id 过大 ,id:{id},self.nowid:{self.nowid}")
def reEnter(self):
self.ss[self.nowid].exit()
self.ss[self.nowid].reset()
self.ss[self.nowid].enter()
def __str__(self):
s = "{ RandomSM:\n"
s += "\n".join(self._strSS())
s += "\n}"
return s
__repr__ = __str__
if __name__ == "__main__":
sm = OrderSM(["a1", "a2", "a3", "a4"])
sm.enter(3)
print(sm)
sm2 = RandomSM(["b1", "b2", "b3", "b4"])
sm2.enter(3)
print(sm2)
print(sm2[2])