【发布时间】:2019-10-22 05:23:12
【问题描述】:
我创建了一个实现 BFS 搜索的通用版本的类:
from collections import deque
class NodeSolver:
'''Class for modeling problems that can be modeled as a directed graph with goal nodes'''
def __init__(self, namer, detector, expander, follower):
'''
Whatever decides to use this gets to define what structure info is.
namer: takes info representing a node and returns a hashable object (the name);
names must be equal if and only if the nodes are equal
detector: takes info and returns True if the node represented by the info is the goal node,
...False otherwise.
expander: takes info and returns an iterable of moves that can be made from the node
...that the info represents. (a.k.a. paths leading out of that node)
follower: takes info and a move that can be made from the node that the info represents,
...and returns the info that represents the node that the move leads to
'''
self.get_name = namer
self.is_goal = detector
self.get_moves = expander
self.follow_move = follower
class BFSSolver(NodeSolver):
'''Class for solving node problems with breadth-first-search to reach the goal node'''
def solve(self, start_info):
'''
Returns the list of moves needed to reach the goal node
...from the node represented by the parameter.
Uses Breadth-first Search to go through the node tree
'''
if self.is_goal(start_info):
return []
start_name = self.get_name(start_info)
# data is in the form (info, path)
name_to_data = {start_name: (start_info, [])}
queue = deque()
queue.appendleft(start_name)
while queue:
current_name = queue.pop()
current_info, current_path = name_to_data[current_name]
expanded_moves = self.get_moves(current_info)
# print("possible moves from {} is {}".format(current_info, expanded_moves))
for move in expanded_moves:
child_info = self.follow_move(current_info, move)
child_path = current_path[:]
child_path.append(move)
if self.is_goal(child_info):
return child_path
child_name = self.get_name(child_info)
if child_name not in name_to_data:
# new, needs to be expanded
name_to_data[child_name] = (child_info, child_path)
queue.appendleft(child_name)
return None
info、move 或 name 的实现完全取决于使用该类的人。
但是,一旦确定了这些定义,那么它们应该保持一致。例如,info 可能是用户创建的 Info 对象类型。 move 可能只是一个整数。 name 可能只是一个字符串。
选择这些定义后,我希望类型检查器能够确保用户坚持这些定义。
如何使用类型检查来完成这样的事情?
现在,我已经完成了:
from collections import deque
from typing import Callable, Any, Iterable, List, Deque, Tuple, Dict, Optional, Hashable
# pylint: disable=invalid-name
# Type definitions
# Can be literally anything
Info = Any
Name = Hashable
# Can be literally anything
Move = Any
# pylint: enable=invalid-name
class NodeSolver:
'''Class for modeling problems that can be modeled as a directed graph with goal nodes'''
def __init__(self, namer: Callable[[Info], Name],
detector: Callable[[Info], bool],
expander: Callable[[Info], Iterable[Move]],
follower: Callable[[Info, Move], Info]):
'''
Whatever decides to use this gets to define what structure info is.
namer: takes info representing a node and returns a hashable object (the name);
names must be equal if and only if the nodes are equal
detector: takes info and returns True if the node represented by the info is the goal node,
...False otherwise.
expander: takes info and returns an iterable of moves that can be made from the node
...that the info represents. (a.k.a. paths leading out of that node)
follower: takes info and a move that can be made from the node that the info represents,
...and returns the info that represents the node that the move leads to
'''
self.get_name = namer
self.is_goal = detector
self.get_moves = expander
self.follow_move = follower
class BFSSolver(NodeSolver):
'''Class for solving node problems with breadth-first-search to reach the goal node'''
def solve(self, start_info: Info) -> Optional[List[Move]]:
'''
Returns the list of moves needed to reach the goal node
...from the node represented by the parameter.
Uses Breadth-first Search to go through the node tree
'''
if self.is_goal(start_info):
return []
start_name = self.get_name(start_info)
# data is in the form (info, path)
name_to_data: Dict[Name, Tuple[Info, List[Move]]] = {start_name: (start_info, [])}
queue: Deque[Name] = deque()
queue.appendleft(start_name)
while queue:
current_name = queue.pop()
current_info, current_path = name_to_data[current_name]
expanded_moves = self.get_moves(current_info)
# print("possible moves from {} is {}".format(current_info, expanded_moves))
for move in expanded_moves:
child_info = self.follow_move(current_info, move)
child_path = current_path[:]
child_path.append(move)
if self.is_goal(child_info):
return child_path
child_name = self.get_name(child_info)
if child_name not in name_to_data:
# new, needs to be expanded
name_to_data[child_name] = (child_info, child_path)
queue.appendleft(child_name)
return None
但是,我不确定使用它的类如何设置这些变量以进行类型检查,我也不确定如果多个类使用具有不同定义 Info 的此类会发生什么情况、Move 和 Name。
另外,我收到关于到处都有Any 的错误。
【问题讨论】:
-
您使用什么工具来检查程序中的类型?
-
Mypy,标记为
标签: python python-3.x typechecking mypy