Key Error: Python Finite State Machine?
Key Error: Python Finite State Machine?
这是我在 Python 中简单实现有限状态机的代码。我有 运行 多次都无济于事。当个体状态 classes 确实继承自个体 class 时,它们无法访问 运行 机器逻辑所需的食物和睡眠变量。我相信我遇到了 KeyError,因为每次我添加新状态时,它都会将当前状态值重置为 None。我怎样才能解决这个错误?是否有 better/proper 方法来构建我的 classes?我处于 python 的中级水平,但是 OOP 概念对我来说特别具有挑战性。任何帮助和建议将不胜感激!
class FSM():
def __init__(self):
self.states = {}
self.c_state = None
def update(self):
self.states[self.c_state].execute()
def addState(self, name, handler):
self.states[name] = handler
def startState(self, state):
self.c_state = state
def changeState(self, newstate):
print('The current state is:', self.c_state)
self.states[self.c_state].exit()
self.c_state = self.states[newstate]
self.states[self.c_state].enter()
class individual():
def __init__(self, name, food, sleep):
self.name = name
self.food = food
self.sleep = sleep
self.fsm = FSM()
class wander(individual):
def enter(self):
print('Entering Wander State')
def execute(self):
print('WANDERING')
if self.sleep == 0:
self.fsm.changeState('SLEEP')
elif 25 > self.sleep > 0 and self.food > 25:
self.fsm.changeState('WANDER')
self.sleep -= 5
self.food -= 5
elif self.food < 25:
self.fsm.changeState('EAT')
def exit(self):
print('Leaving Wander State')
class eat(individual):
def enter(self):
print('Entering Eating State')
def execute(self):
print('EATING')
if self.sleep > 0 and self.food < 25:
self.fsm.changeState('EAT')
self.food += 5
self.sleep -= 5
elif self.food > 25 and self.sleep > 0:
self.fsm.changeState('WANDER')
elif self.sleep == 0:
self.fsm.changeState('SLEEP')
def exit(self):
print('Exiting Eating State')
class sleep(individual):
def enter(self):
print('Entering Sleeping State')
def execute(self):
print('SLEEPING')
if 50 > self.sleep > 0:
self.fsm.changeState('SLEEP')
self.sleep += 5
elif self.sleep == 50 and self.food < 25:
self.fsm.changeState('EAT')
elif self.sleep == 50 and self.food > 25:
self.fsm.changeState('WANDER')
def exit(self):
print('Exiting Sleeping State')
aaron = individual('aaron', 10, 30)
aaron.fsm.addState('WANDER', wander(aaron.name, aaron.food, aaron.sleep))
aaron.fsm.addState('EAT', eat(aaron.name, aaron.food, aaron.sleep))
aaron.fsm.addState('SLEEP', sleep(aaron.name, aaron.food, aaron.sleep))
aaron.fsm.startState('WANDER')
print(aaron.fsm.c_state)
aaron.fsm.update()
File "C:/Users/Aaron/PycharmProjects/InDepthFSM/FSM.py", line 12, in update
self.states[self.c_state].execute()
File "C:/Users/Aaron/PycharmProjects/InDepthFSM/FSM.py", line 50, in execute
self.fsm.changeState('EAT')
File "C:/Users/Aaron/PycharmProjects/InDepthFSM/FSM.py", line 24, in changeState
self.states[self.c_state].exit()
KeyError: None
这里的问题是您在执行更新时指的是不同的 fsm 对象。
在 execute
代码片段中,当您更新状态时,问题是虽然 FSM
对象存在于单个对象中,但它不存在于 eat
中class,你尝试更新 eat
class.
的状态
# Here, since self refers to the `eat` class, you are creating a new fsm object
# This means that you are in fact referring to an empty set of states.
elif self.sleep == 0:
self.fsm.changeState('SLEEP')
继承并不意味着classes共享一个FSM
实例,所以如果你想对属于个体class的FSM
对象进行操作] 您需要将个人作为输入传递。
也就是说,这里的eat
块真的不应该是class,而应该是individual
的一个函数,而不是从它继承。例如:
class individual(object):
def __init__(self, ...):
# make object
def eat(self):
print('EATING')
if self.sleep > 0 and self.food < 25:
self.fsm.changeState('EAT')
self.food += 5
self.sleep -= 5
elif self.food > 25 and self.sleep > 0:
self.fsm.changeState('WANDER')
elif self.sleep == 0:
self.fsm.changeState('SLEEP')
在这种情况下,self
实际上指的是 individual
对象。
我认为您一般对 OOP 有一些困惑。继承根本不与特定对象实例交互。相反,它就像在说:"I need to make a new object, but let me use this old one as a template and just add to it".
您在这里尝试做的事情更接近于创建单例,单例是一个对象,具有在别处引用的单一状态。并非所有东西都应该是对象。例如,处理程序通常是函数,依赖魔法 execute
函数而不是仅仅执行函数是相当迂回的。
正如 Slater Tyranus 提到的,问题是您正在使状态 (wander
、eat
和 sleep
classes) subclass individual
的 es。这是不正确的。把 subclassing 想成是在说 "is" 别的东西。例如,使用 class 声明 class Car(Vehicle):
,您实际上是在说 "a Car
is a Vehicle
",这是一个正确的陈述。但是,您的代码暗示 wander
状态是个人,这是不正确的。另一个问题是因为每个状态都是一个个体,每个状态都有自己的 fsm。这不是必需的,个人也不应该首先拥有 fsm(你有吗?我没有)。
我重构了你的代码,简化了状态中的条件,更正了过程中的其他一些错误。看看这是否更符合您的预期:
class FSM(object):
def __init__(self, individual):
self.states = {}
self.c_state = None
self.individual = individual
def update(self):
self.states[self.c_state].execute(self)
def addState(self, name, handler):
self.states[name] = handler
def startState(self, state):
self.c_state = state
def changeState(self, newstate):
print('The current state is:', self.c_state)
self.states[self.c_state].exit()
self.c_state = newstate
self.states[self.c_state].enter()
class Individual(object):
def __init__(self, name, food, sleep):
self.name = name
self.food = food
self.sleep = sleep
class Wander():
@staticmethod
def enter():
print('Entering Wander State')
@staticmethod
def execute(fsm):
print('WANDERING')
if fsm.individual.sleep <= 0:
fsm.changeState('SLEEP')
elif fsm.individual.food >= 25:
fsm.changeState('WANDER')
fsm.individual.sleep -= 5
fsm.individual.food -= 5
else:
fsm.changeState('EAT')
@staticmethod
def exit():
print('Leaving Wander State')
class Eat():
@staticmethod
def enter():
print('Entering Eating State')
@staticmethod
def execute(fsm):
print('EATING')
if fsm.individual.sleep <= 0:
fsm.changeState('SLEEP')
elif fsm.individual.food < 25:
fsm.changeState('EAT')
fsm.individual.food += 5
fsm.individual.sleep -= 5
else:
fsm.changeState('WANDER')
@staticmethod
def exit():
print('Exiting Eating State')
class Sleep():
@staticmethod
def enter():
print('Entering Sleeping State')
@staticmethod
def execute(fsm):
print('SLEEPING')
if fsm.individual.sleep < 50:
fsm.changeState('SLEEP')
fsm.individual.sleep += 5
elif fsm.individual.food < 25:
fsm.changeState('EAT')
else:
fsm.changeState('WANDER')
@staticmethod
def exit():
print('Exiting Sleeping State')
aaron = Individual('aaron', 10, 30)
fsm = FSM(aaron)
fsm.addState('WANDER', Wander)
fsm.addState('EAT', Eat)
fsm.addState('SLEEP', Sleep)
fsm.startState('WANDER')
print(fsm.c_state)
fsm.update()
这是我在 Python 中简单实现有限状态机的代码。我有 运行 多次都无济于事。当个体状态 classes 确实继承自个体 class 时,它们无法访问 运行 机器逻辑所需的食物和睡眠变量。我相信我遇到了 KeyError,因为每次我添加新状态时,它都会将当前状态值重置为 None。我怎样才能解决这个错误?是否有 better/proper 方法来构建我的 classes?我处于 python 的中级水平,但是 OOP 概念对我来说特别具有挑战性。任何帮助和建议将不胜感激!
class FSM():
def __init__(self):
self.states = {}
self.c_state = None
def update(self):
self.states[self.c_state].execute()
def addState(self, name, handler):
self.states[name] = handler
def startState(self, state):
self.c_state = state
def changeState(self, newstate):
print('The current state is:', self.c_state)
self.states[self.c_state].exit()
self.c_state = self.states[newstate]
self.states[self.c_state].enter()
class individual():
def __init__(self, name, food, sleep):
self.name = name
self.food = food
self.sleep = sleep
self.fsm = FSM()
class wander(individual):
def enter(self):
print('Entering Wander State')
def execute(self):
print('WANDERING')
if self.sleep == 0:
self.fsm.changeState('SLEEP')
elif 25 > self.sleep > 0 and self.food > 25:
self.fsm.changeState('WANDER')
self.sleep -= 5
self.food -= 5
elif self.food < 25:
self.fsm.changeState('EAT')
def exit(self):
print('Leaving Wander State')
class eat(individual):
def enter(self):
print('Entering Eating State')
def execute(self):
print('EATING')
if self.sleep > 0 and self.food < 25:
self.fsm.changeState('EAT')
self.food += 5
self.sleep -= 5
elif self.food > 25 and self.sleep > 0:
self.fsm.changeState('WANDER')
elif self.sleep == 0:
self.fsm.changeState('SLEEP')
def exit(self):
print('Exiting Eating State')
class sleep(individual):
def enter(self):
print('Entering Sleeping State')
def execute(self):
print('SLEEPING')
if 50 > self.sleep > 0:
self.fsm.changeState('SLEEP')
self.sleep += 5
elif self.sleep == 50 and self.food < 25:
self.fsm.changeState('EAT')
elif self.sleep == 50 and self.food > 25:
self.fsm.changeState('WANDER')
def exit(self):
print('Exiting Sleeping State')
aaron = individual('aaron', 10, 30)
aaron.fsm.addState('WANDER', wander(aaron.name, aaron.food, aaron.sleep))
aaron.fsm.addState('EAT', eat(aaron.name, aaron.food, aaron.sleep))
aaron.fsm.addState('SLEEP', sleep(aaron.name, aaron.food, aaron.sleep))
aaron.fsm.startState('WANDER')
print(aaron.fsm.c_state)
aaron.fsm.update()
File "C:/Users/Aaron/PycharmProjects/InDepthFSM/FSM.py", line 12, in update
self.states[self.c_state].execute()
File "C:/Users/Aaron/PycharmProjects/InDepthFSM/FSM.py", line 50, in execute
self.fsm.changeState('EAT')
File "C:/Users/Aaron/PycharmProjects/InDepthFSM/FSM.py", line 24, in changeState
self.states[self.c_state].exit()
KeyError: None
这里的问题是您在执行更新时指的是不同的 fsm 对象。
在 execute
代码片段中,当您更新状态时,问题是虽然 FSM
对象存在于单个对象中,但它不存在于 eat
中class,你尝试更新 eat
class.
# Here, since self refers to the `eat` class, you are creating a new fsm object
# This means that you are in fact referring to an empty set of states.
elif self.sleep == 0:
self.fsm.changeState('SLEEP')
继承并不意味着classes共享一个FSM
实例,所以如果你想对属于个体class的FSM
对象进行操作] 您需要将个人作为输入传递。
也就是说,这里的eat
块真的不应该是class,而应该是individual
的一个函数,而不是从它继承。例如:
class individual(object):
def __init__(self, ...):
# make object
def eat(self):
print('EATING')
if self.sleep > 0 and self.food < 25:
self.fsm.changeState('EAT')
self.food += 5
self.sleep -= 5
elif self.food > 25 and self.sleep > 0:
self.fsm.changeState('WANDER')
elif self.sleep == 0:
self.fsm.changeState('SLEEP')
在这种情况下,self
实际上指的是 individual
对象。
我认为您一般对 OOP 有一些困惑。继承根本不与特定对象实例交互。相反,它就像在说:"I need to make a new object, but let me use this old one as a template and just add to it".
您在这里尝试做的事情更接近于创建单例,单例是一个对象,具有在别处引用的单一状态。并非所有东西都应该是对象。例如,处理程序通常是函数,依赖魔法 execute
函数而不是仅仅执行函数是相当迂回的。
正如 Slater Tyranus 提到的,问题是您正在使状态 (wander
、eat
和 sleep
classes) subclass individual
的 es。这是不正确的。把 subclassing 想成是在说 "is" 别的东西。例如,使用 class 声明 class Car(Vehicle):
,您实际上是在说 "a Car
is a Vehicle
",这是一个正确的陈述。但是,您的代码暗示 wander
状态是个人,这是不正确的。另一个问题是因为每个状态都是一个个体,每个状态都有自己的 fsm。这不是必需的,个人也不应该首先拥有 fsm(你有吗?我没有)。
我重构了你的代码,简化了状态中的条件,更正了过程中的其他一些错误。看看这是否更符合您的预期:
class FSM(object):
def __init__(self, individual):
self.states = {}
self.c_state = None
self.individual = individual
def update(self):
self.states[self.c_state].execute(self)
def addState(self, name, handler):
self.states[name] = handler
def startState(self, state):
self.c_state = state
def changeState(self, newstate):
print('The current state is:', self.c_state)
self.states[self.c_state].exit()
self.c_state = newstate
self.states[self.c_state].enter()
class Individual(object):
def __init__(self, name, food, sleep):
self.name = name
self.food = food
self.sleep = sleep
class Wander():
@staticmethod
def enter():
print('Entering Wander State')
@staticmethod
def execute(fsm):
print('WANDERING')
if fsm.individual.sleep <= 0:
fsm.changeState('SLEEP')
elif fsm.individual.food >= 25:
fsm.changeState('WANDER')
fsm.individual.sleep -= 5
fsm.individual.food -= 5
else:
fsm.changeState('EAT')
@staticmethod
def exit():
print('Leaving Wander State')
class Eat():
@staticmethod
def enter():
print('Entering Eating State')
@staticmethod
def execute(fsm):
print('EATING')
if fsm.individual.sleep <= 0:
fsm.changeState('SLEEP')
elif fsm.individual.food < 25:
fsm.changeState('EAT')
fsm.individual.food += 5
fsm.individual.sleep -= 5
else:
fsm.changeState('WANDER')
@staticmethod
def exit():
print('Exiting Eating State')
class Sleep():
@staticmethod
def enter():
print('Entering Sleeping State')
@staticmethod
def execute(fsm):
print('SLEEPING')
if fsm.individual.sleep < 50:
fsm.changeState('SLEEP')
fsm.individual.sleep += 5
elif fsm.individual.food < 25:
fsm.changeState('EAT')
else:
fsm.changeState('WANDER')
@staticmethod
def exit():
print('Exiting Sleeping State')
aaron = Individual('aaron', 10, 30)
fsm = FSM(aaron)
fsm.addState('WANDER', Wander)
fsm.addState('EAT', Eat)
fsm.addState('SLEEP', Sleep)
fsm.startState('WANDER')
print(fsm.c_state)
fsm.update()