2017-06-02 2 views
0

Ich schrieb eine StateMachine Klasse in Python, so dass es vererbt werden konnte. Die Logik funktioniert wie erwartet, aber ich kann auf das Attribut self.data von einem State zugreifen, das in der abgeleiteten StateMachine-Klasse mit dem Namen StateMachineTest vorhanden ist.Python-Klasse Vererbung, attributeError

Der folgende Fehler wird generiert:

 
Traceback (most recent call last): 
File "/home/nbout/work/python/state_machine/main.py", line 68, in 
    main() 
File "/home/nbout/work/python/state_machine/main.py", line 59, in main 
    test = StateMachineTest() 
File "/home/nbout/work/python/state_machine/main.py", line 47, in __init__ 
    StateMachine.__init__(self, Started()) 
File "/home/nbout/work/python/state_machine/state_machine.py", line 17, in _init__ 
    self.current_state.on_enter(self) 
File "/home/nbout/work/python/state_machine/main.py", line 16, in on_enter 
    print("Started: data:{}".format(sm_test.data)) 
Started: on_enter 
AttributeError: 'StateMachineTest' object has no attribute 'data' 
Started: on_exit 

state_machine.py

class State: 

    def on_enter(self, state_machine): 
     pass 

    def on_exit(self, state_machine): 
     pass 


class StateMachine: 

    def __init__(self, start_state): 
     self.current_state = start_state 

     self.current_state.on_enter(self) 

    def __del__(self): 
     self.current_state.on_exit(self) 

    def set_state(self, state): 

     self.current_state.on_exit(self) 
     self.current_state = state 
     self.current_state.on_enter(self) 

main.py

from state_machine import StateMachine 
from state_machine import State 


class StateTest(State): 
    def pause(self, state_machine_test): 
     pass 

    def start(self, state_machine_test): 
     pass 


class Started(StateTest): 
    def on_enter(self, sm_test): 
     print("Started: on_enter") 
     print("Started: data:{}".format(sm_test.data)) 

    def on_exit(self, sm_test): 
     print("Started: on_exit") 

    def pause(self, sm_test): 
     print("Started: pause") 
     sm_test.set_state(Paused()) 

    def start(self, sm_test): 
     print("Started: start") 


class Paused(StateTest): 
    def on_enter(self, sm_test): 
     print("Paused: on_enter") 

    def on_exit(self, sm_test): 
     print("Paused: on_exit") 

    def pause(self, sm_test): 
     print("Paused: pause") 

    def start(self, sm_test): 
     print("Paused: start") 
     sm_test.set_state(Started()) 


class StateMachineTest(StateMachine): 

    def __init__(self): 
     StateMachine.__init__(self, Started()) 
     self.data = 10 

    def pause(self): 
     self.current_state.pause(self) 

    def start(self): 
     self.current_state.start(self) 


def main(): 

    test = StateMachineTest() 

    test.start() 
    test.pause() 
    test.pause() 
    test.start() 


if __name__ == '__main__': 
    main() 

Antwort

0

Ihr Problem liegt in der Tatsache, dass StateMachine.__init__(self, Started()) erfordert self ‚s data atttribute bereits eingestellt werden, aber Sie setzen es nur um die nächste Zeile (self.data = 10). Schalten Sie diese beiden Zeilen um und versuchen Sie es erneut!

+0

Das ist die Lösung, danke. Ich werde Ihre Antwort akzeptieren, sobald StackOverflow mich ... – nbout

0

Wow, ist dieser Code wirklich unnötig kompliziert.

Das Problem scheint zu sein, dass Sie Started im __init__ Ihrer StateMachineTest Klasse initialisieren, so dass seine on_enter läuft, bevor Sie self.data gesetzt haben.

Sie können dies beheben, indem Sie die Zuweisung self.data über den super Aufruf verschieben, aber eine viel bessere Wette wäre, Ihre Vererbungshierarchie zu vereinfachen.

+0

Danke, das war mein Problem. Ich verwendete die Vererbung auf diese Weise, um die Wiederverwendbarkeit der 'StateMachine'-Klasse zu erzwingen – nbout