2

I'm making a simple text-based game. My full code is 150 lines, so I'll include what I think is relevant. Let me know if you need more.

The problem is that this line:

print("You deal " + str(hero.damage) + " damage to the monster")

returns only 5 instead of 5 + level as wanted.

class Hero:

    def __init__(self):
        self.level = 0
        self.damage = 5 + self.level #This is the problem line. Self.level seems to be treated as equal to 0 even when it is higher than 0.
        self.experience = 0
    def level_up(self): #triggered on monster death
        xp_required = 15
        if self.experience >= xp_required:
            self.level += 1
hero = Hero()

I know hero.level_up() is successful because:

print(hero.level)

returns a level that gets correctly updated as appropriate.

I'm guessing either:

self.damage only gets calculated once, then stores that value even after components of it have changed.

or:

There is some kind of issue with calling __init__ values within __init__.

or:

The calculation is done on the class Hero, not the object Hero()

2
  • 3
    Mind that self.damage= 5+self.level is an assignment. Not an equation. After it is executed, it is not updated anymore. You need to do that yourself. Commented Mar 26, 2017 at 23:49
  • Thanks dude. Problem fixed. Simply copy paste: self.damage = 5 + self.level into level_up(). If you want to add your comment as an answer, I'll mark it as answered. damn.. I was nearly there. I actually mentioned the answer in my original question, at the bottum XD. Just didn't direct my attention there enough because I wasn't sure which of the problems it was, and figured it might've been a different problem also. Commented Mar 26, 2017 at 23:57

2 Answers 2

7

You are right, self.damage is only written to once: In the __init__ constructor which is itself only called once (when the object is created). And at that time, self.level is zero, so self.damage will be always 5.

You have two options:

  1. Either you change your code to always update the damage as well whenever you change the level. In order to avoid spreading the damage calculation logic into multiple places, you would create a helper method to update the damage value:

    def update_damage(self):
        self.damage = 5 + self.level
    
    def level_up(self):
        if self.experience <= 15:
            self.level += 1
            self.update_damage()
    

    If the damage value is only ever dependent on the level, you could also make it a update_level(new_level) method; but I opted out of that solution here since it’s not uncommon to have some other things affect damage later on as well (e.g. damage potions or whatever).

  2. Or you change damage into a calculated property, so the damage value is calculated whenever you access it. That has the overhead that it needs to be calculated every time instead of the value being stored somewhere, but on the other hand, you have the ultimate truth about the damage value and you do not need to remember to update it elsewhere:

    def __init__(self):
        self.level = 0
        self.experience = 0 
    
    @property
    def damage(self):
        return 5 + self.level
    
Sign up to request clarification or add additional context in comments.

3 Comments

I didn't know about @property. That seems really useful for a few situations.
@Unlocked Indeed, properties replace getters and setters (yes, setters too!) with a more natural interface to access or store values, making them very useful (and pythonic). For more on that topic, see also When and how to use the builtin function property() in python and How does the property decorator work?
Your post taught me two things. Thanks :). 1: variables are stored once and that's final. 2: @property is a thing.
5

Your guess about self.damage being calculated once is correct. As @Willem Van Onsem mentions, self.damage= 5+self.level is an assignment and not an equation. You will need to manually update it each time you change self.level.

The most suitable approach to me seems to be wrap it into a property such as:

@property
def damage(self):
    return 5 + self.level

The way that you are treating equality is more closely related to reactive programming which is often emulated with properties in python.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.