关键错误:Python有限状态机?

时间:2015-04-07 19:22:26

标签: python oop fsm

这是我在Python中简单实现有限状态机的代码。我多次运行它无济于事。当各个州的类继承自单个类时,它们无法访问运行机器逻辑所需的食物和睡眠变量。我相信我得到的是KeyError,因为每次添加新状态时,它都会将Current State Value重置为None。我怎么能解决这个错误?是否有更好/正确的方法来构建我的课程?我是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

2 个答案:

答案 0 :(得分:1)

这里的问题是,当您执行更新时,您将引用不同的fsm对象。

execute代码段中,当您更新状态时,问题是虽然单个对象存在FSM对象,但eat类不存在,并尝试更新eat类的状态。

# 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')

继承并不意味着这些类共享一个FSM实例,因此如果您想对属于该类的FSM对象进行操作,则需要将该个体作为输入传递。

那就是说,这里的eat件确实不应该是一个类,而应该是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有一些混淆。继承不与特定对象实例进行交互。相反,它就像是说:“我需要创建一个新对象,但让我使用这个旧对象作为模板,然后添加它”。

你在这里尝试做的更接近于创建一个单例,这是一个具有单个状态的对象,在其他地方被引用。并非一切都应该是一个对象。例如,处理程序通常是函数,依赖于一个神奇的execute函数,而不仅仅是执行一个函数是非常迂回的。

答案 1 :(得分:0)

正如Slater Tyranus所提到的,问题在于你正在制作wander的状态(eatsleepindividual类)子类。这是不正确的。把子类化想象成某事&#34;是&#34;别的。例如,对于类声明class Car(Vehicle):,您基本上是说&#34; CarVehicle&#34;,这是一个真实的陈述。但是,您的代码暗示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()