2016-04-28 5 views
2

Meine vereinfachte .kv Datei:Warum bekomme ich "NoneType" -Objekt hat kein Attribut in. Kv-Datei?

<GameWorld>: 
    player: the_player 

    canvas: 
     Rectangle: 
      pos: 5, root.top - 25 
      size: self.player.health, 20 # error raised in this line 

    Player: 
     id: the_player 
     center: self.center 

Meine vereinfachte Python-Datei:

class Player(Widget): 
    health = NumericProperty(50) 

    def __init__(self, **kwargs): 
     super(Player, self).__init__(**kwargs) 
     self.health = 100 

class GameWorld(Widget): 
    player = ObjectProperty() 
    entities = ListProperty() 

    def __init__(self, **kwargs): 
     super(GameWorld, self).__init__(**kwargs) 
     self.entities.append(self.player) 

Der Fehler erhalte ich:

AttributeError: 'NoneType' object has no attribute 'health' 

Kivy denkt self.playerNone ist. Bitte hilf mir zu verstehen, was falsch ist.

+0

neuen Stil Klassen IIRC werden Sie nicht durch 'self' tun Verweise auf Klassenmitglieder lassen. Benutze 'GameWorld.player'. Oder möglicherweise 'self .__ class __. Player'. –

+0

ich hoffe [this] (http://stackoverflow.com/questions/10789296/attributeerror-nonetype-object-has-no-attribute-health) alter Beitrag kann Ihr Problem beantworten. – Spiderman

+0

@BrianCain Ich dachte dasselbe (und schrieb eine Antwort auf diesen Effekt), aber das Testen in einer Shell zeigt an, dass das nicht korrekt ist. –

Antwort

1

Wenn die canvas Anweisungen ausgewertet werden, ist GameWorld.player immer noch None, die Standardeinstellung für ObjectProperty, daher der Fehler.

Wenn Sie einen Test für None an der kv-Regel wie folgt hinzu:

<GameWorld>: 
    player: the_player 
    canvas: 
     Rectangle: 
      pos: 5, root.top - 25 
      size: self.player is not None and self.player.health, 20 

Kein Fehler wird geworfen, aber die automatische Bindung wird nicht durchgeführt werden. Wenn Sie jedoch hinzufügen rebind=True auf die Erklärung des ObjectProperty:

class GameWorld(Widget): 
    player = ObjectProperty(rebind=True) 

dies korrekt funktionieren.


Weggehen weniger elegant alternative Lösungen bis:

Sie könnten ein Player Objekt an Definition instanziiert:

class GameWorld(Widget): 
    player = ObjectProperty(Player()) 

Oder Sie eine andere NumericProperty-GameWorld, mit dem alleinigen Zweck des Seins könnte hinzufügen gebunden an player.health, aber initialisiert auf einen vernünftigen Wert:

class GameWorld(Widget): 
    _player_health = NumericProperty(1) 

und

<GameWorld>: 
    player: the_player 
    _player_health: the_player.health 

    canvas: 
     Rectangle: 
      pos: 5, root.top - 25 
      size: self._player_health, 20 
+0

Ich verstehe. Gibt es einen Grund, warum die Canvas-Anweisungen ausgeführt werden, bevor die Eigenschaften festgelegt werden? Gibt es eine Möglichkeit, das zu ändern? –

+0

@ AvivCohn siehe bearbeiten für bessere Art, es automatisch zu tun – zeeMonkeez

+0

Danke für die neuere Lösung, es ist großartig. Eine Frage allerdings: Warum ist 'self.player is not None und self.player.health'? In einer Python-Shell wird ein boolescher Wert ausgewertet. Was tut es? –

Verwandte Themen