Aviv Cohn
Aviv Cohn

Reputation: 17193

Why am I getting `'NoneType' object has no attribute` in .kv file?

My simplified .kv file:

<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

My simplified Python file:

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)

The error I get:

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

Kivy thinks self.player is None. Please help me understand what's wrong.

Upvotes: 2

Views: 607

Answers (1)

zeeMonkeez
zeeMonkeez

Reputation: 5157

When the canvas instructions are evaluated, GameWorld.player is still None, the default for ObjectProperty, hence the error.

If you add a test for None to the kv rule like this:

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

No error will be thrown, but automatic binding will not be performed. However, if you add rebind=True to the declaration of the ObjectProperty:

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

this will work correctly.


Leaving less elegant alternate solutions up:

You could instantiate a Player object at definition:

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

Or, you could add another NumericProperty to GameWorld, with the sole purpose of being bound to player.health, but initialized to a sensible value:

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

and

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

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

Upvotes: 1

Related Questions