图搜索模式和层次状态机模式 21/30 | Python 主题月
写在前面
本文正在参加「Python主题月」,详情查看活动链接
这个月是 Python 活动月,我决定尝试用 Python 来刷这 30 天的每日一题和随机一题。然后如果周末有精力,我想捣鼓捣鼓这个python-patterns
设计模式对我来说更多的是学习而不是我的个人经验总结,所以我很可能理解偏,如果有大佬见到了请及时指出,我之所以选择在掘金来写一些个人的东西是因为这里的文章质量更高,我不希望后来者看到了这些文章被误导。
图搜索模式
class GraphSearch:
"""Graph search emulation in python, from source
http://www.python.org/doc/essays/graphs/
dfs stands for Depth First Search
bfs stands for Breadth First Search"""
def __init__(self, graph):
self.graph = graph
def find_path_dfs(self, start, end, path=None):
path = path or []
path.append(start)
if start == end:
return path
for node in self.graph.get(start, []):
if node not in path:
newpath = self.find_path_dfs(node, end, path[:])
if newpath:
return newpath
def find_all_paths_dfs(self, start, end, path=None):
path = path or []
path.append(start)
if start == end:
return [path]
paths = []
for node in self.graph.get(start, []):
if node not in path:
newpaths = self.find_all_paths_dfs(node, end, path[:])
paths.extend(newpaths)
return paths
def find_shortest_path_dfs(self, start, end, path=None):
path = path or []
path.append(start)
if start == end:
return path
shortest = None
for node in self.graph.get(start, []):
if node not in path:
newpath = self.find_shortest_path_dfs(node, end, path[:])
if newpath:
if not shortest or len(newpath) < len(shortest):
shortest = newpath
return shortest
def find_shortest_path_bfs(self, start, end):
queue = [start]
dist_to = {start: 0}
edge_to = {}
if start == end:
return queue
while len(queue):
value = queue.pop(0)
for node in self.graph[value]:
if node not in dist_to.keys():
edge_to[node] = value
dist_to[node] = dist_to[value] + 1
queue.append(node)
if end in edge_to.keys():
path = []
node = end
while dist_to[node] != 0:
path.insert(0, node)
node = edge_to[node]
path.insert(0, start)
return path
def main():
"""
# example of graph usage
>>> graph = {
... 'A': ['B', 'C'],
... 'B': ['C', 'D'],
... 'C': ['D', 'G'],
... 'D': ['C'],
... 'E': ['F'],
... 'F': ['C'],
... 'G': ['E'],
... 'H': ['C']
... }
# initialization of new graph search object
>>> graph_search = GraphSearch(graph)
>>> print(graph_search.find_path_dfs('A', 'D'))
['A', 'B', 'C', 'D']
# start the search somewhere in the middle
>>> print(graph_search.find_path_dfs('G', 'F'))
['G', 'E', 'F']
# unreachable node
>>> print(graph_search.find_path_dfs('C', 'H'))
None
# non existing node
>>> print(graph_search.find_path_dfs('C', 'X'))
None
>>> print(graph_search.find_all_paths_dfs('A', 'D'))
[['A', 'B', 'C', 'D'], ['A', 'B', 'D'], ['A', 'C', 'D']]
>>> print(graph_search.find_shortest_path_dfs('A', 'D'))
['A', 'B', 'D']
>>> print(graph_search.find_shortest_path_dfs('A', 'F'))
['A', 'C', 'G', 'E', 'F']
>>> print(graph_search.find_shortest_path_bfs('A', 'D'))
['A', 'B', 'D']
>>> print(graph_search.find_shortest_path_bfs('A', 'F'))
['A', 'C', 'G', 'E', 'F']
# start the search somewhere in the middle
>>> print(graph_search.find_shortest_path_bfs('G', 'F'))
['G', 'E', 'F']
# unreachable node
>>> print(graph_search.find_shortest_path_bfs('A', 'H'))
None
# non existing node
>>> print(graph_search.find_shortest_path_bfs('A', 'X'))
None
"""
if __name__ == "__main__":
import doctest
doctest.testmod()
层次状态机模式
class UnsupportedMessageType(BaseException):
pass
class UnsupportedState(BaseException):
pass
class UnsupportedTransition(BaseException):
pass
class HierachicalStateMachine:
def __init__(self):
self._active_state = Active(self) # Unit.Inservice.Active()
self._standby_state = Standby(self) # Unit.Inservice.Standby()
self._suspect_state = Suspect(self) # Unit.OutOfService.Suspect()
self._failed_state = Failed(self) # Unit.OutOfService.Failed()
self._current_state = self._standby_state
self.states = {
"active": self._active_state,
"standby": self._standby_state,
"suspect": self._suspect_state,
"failed": self._failed_state,
}
self.message_types = {
"fault trigger": self._current_state.on_fault_trigger,
"switchover": self._current_state.on_switchover,
"diagnostics passed": self._current_state.on_diagnostics_passed,
"diagnostics failed": self._current_state.on_diagnostics_failed,
"operator inservice": self._current_state.on_operator_inservice,
}
def _next_state(self, state):
try:
self._current_state = self.states[state]
except KeyError:
raise UnsupportedState
def _send_diagnostics_request(self):
return "send diagnostic request"
def _raise_alarm(self):
return "raise alarm"
def _clear_alarm(self):
return "clear alarm"
def _perform_switchover(self):
return "perform switchover"
def _send_switchover_response(self):
return "send switchover response"
def _send_operator_inservice_response(self):
return "send operator inservice response"
def _send_diagnostics_failure_report(self):
return "send diagnostics failure report"
def _send_diagnostics_pass_report(self):
return "send diagnostics pass report"
def _abort_diagnostics(self):
return "abort diagnostics"
def _check_mate_status(self):
return "check mate status"
def on_message(self, message_type): # message ignored
if message_type in self.message_types.keys():
self.message_types[message_type]()
else:
raise UnsupportedMessageType
class Unit:
def __init__(self, HierachicalStateMachine):
self.hsm = HierachicalStateMachine
def on_switchover(self):
raise UnsupportedTransition
def on_fault_trigger(self):
raise UnsupportedTransition
def on_diagnostics_failed(self):
raise UnsupportedTransition
def on_diagnostics_passed(self):
raise UnsupportedTransition
def on_operator_inservice(self):
raise UnsupportedTransition
class Inservice(Unit):
def __init__(self, HierachicalStateMachine):
self._hsm = HierachicalStateMachine
def on_fault_trigger(self):
self._hsm._next_state("suspect")
self._hsm._send_diagnostics_request()
self._hsm._raise_alarm()
def on_switchover(self):
self._hsm._perform_switchover()
self._hsm._check_mate_status()
self._hsm._send_switchover_response()
class Active(Inservice):
def __init__(self, HierachicalStateMachine):
self._hsm = HierachicalStateMachine
def on_fault_trigger(self):
super().perform_switchover()
super().on_fault_trigger()
def on_switchover(self):
self._hsm.on_switchover() # message ignored
self._hsm.next_state("standby")
class Standby(Inservice):
def __init__(self, HierachicalStateMachine):
self._hsm = HierachicalStateMachine
def on_switchover(self):
super().on_switchover() # message ignored
self._hsm._next_state("active")
class OutOfService(Unit):
def __init__(self, HierachicalStateMachine):
self._hsm = HierachicalStateMachine
def on_operator_inservice(self):
self._hsm.on_switchover() # message ignored
self._hsm.send_operator_inservice_response()
self._hsm.next_state("suspect")
class Suspect(OutOfService):
def __init__(self, HierachicalStateMachine):
self._hsm = HierachicalStateMachine
def on_diagnostics_failed(self):
super().send_diagnostics_failure_report()
super().next_state("failed")
def on_diagnostics_passed(self):
super().send_diagnostics_pass_report()
super().clear_alarm() # loss of redundancy alarm
super().next_state("standby")
def on_operator_inservice(self):
super().abort_diagnostics()
super().on_operator_inservice() # message ignored
class Failed(OutOfService):
"""No need to override any method."""
def __init__(self, HierachicalStateMachine):
self._hsm = HierachicalStateMachine
小结
参考文献
- 无