2

I have the following code :

class Potion(object):
    def __init__(self,name,var,varamount):
        self.name=name
        self.var=var
        self.varamount=varamount

class Inventory(object):
    def __init__(self):
        self.items={}
    def use_potion(self,potion):
        potion.var+=potion.varamount
        print("Used a ",potion.name," !")

class Player():
    def __init__(self):
        self.health=100
        self.mana=100
        self.stamina=100

inventory=Inventory()
player=Player()
healthpotion=Potion("Health potion",player.health,50)
inventory.use_potion(healthpotion)

Here, my health potion is supposed to add 50 to the variable player.health. But player.health remains unchanged, only healthpotion.var is changed. Assuming I want different types of potions (stamina, mana, health), how can I dynamically assign player.health, player.stamina and player.mana to potion.var ?

5
  • Just tested it, upon print(healthpotion.var) it prints 150 so it is working. I'd suggest you test and come back with the exact question you had in mind. Commented Dec 16, 2018 at 10:07
  • 2
    It's probably worth reading this as a starting point: nedbatchelder.com/text/names1.html Commented Dec 16, 2018 at 10:08
  • My bad, updated the question. Should be more clear now. Commented Dec 16, 2018 at 10:09
  • By potion.var+=potion.varamount, you mean setattr(player, potion.var, getattr(player, potion.var) + potion.varamount) where potion.var == "health"? Commented Dec 16, 2018 at 10:15
  • You should go through a tutorial, focusing on how Python expressions are used and evaluated. Hint: player.health is evaluated to 100 when you send it to the Potion constructor. It doesn't persist as a pointer or reference to that variable. Commented Dec 16, 2018 at 10:42

4 Answers 4

2

The reason this does not work is that you have passed the argument player.health to the Potion, this is the same as to write:

Potion("Health potion",100,50)
Sign up to request clarification or add additional context in comments.

2 Comments

Then how can I assign the variable player.health, not its value ?
You should either pass the object "player" itself and set player.health in the function or implement this differently
0

You need to send created instance of Player, not just value of their attribute:

class Potion(object):
    def __init__(self,name,var,varamount):
        self.name=name
        self.var=var
        self.varamount=varamount

class Inventory(object):
    def __init__(self):
        self.items={}
    def use_potion(self,potion):
        # Your potion.var contains Player instance. Access players health.
        potion.var.health += potion.varamount
        print("Used a ",potion.name," !")

class Player():
    def __init__(self):
        self.health=100
        self.mana=100
        self.stamina=100

inventory=Inventory()
player=Player()
healthpotion=Potion("Health potion",player,50) # Send player instance.
print(player.health) # 100
inventory.use_potion(healthpotion)
print(player.health) # 150

2 Comments

That's a solution, but it only works for one type of potion : health. How can I do this with every potion type ?
You can add if else statements to your use_potion method. For example, if potion.name == "Health potion": potion.var.health += potion.varamount. For some negative potion, just subtract.
0

You using objects. Objects 'know' things - the values of their attibutes - and objects can send messages to each other - by calling their methods.

In this case:

  • Player knows their health.
  • Potion knows how much it can increase health by
  • Inventory knows whether or not the it has a potion.
  • Player should have an inventory
  • Player can choose to use items in its inventory
  • Inventory keeps track of whether an item has been used

Based on these facts, we know which methods and attributes our classes need.

Potion needs to know how many health points it can restore

class Potion(object):

    def __init__(self,name, varamount):
        self.name=name
        self.varamount=varamount

Inventory needs to be able to keep track of its contents.

class Inventory(object):
    def __init__(self):
        self.items={}

    def add_potion(self, potion):
        self.items['potion'] = potion

    def get_potion(self):
         return self.items.get('potion')

    def remove_potion(self):
        self.items.pop('potion', None)

Player needs to be able to track its health, and use potions.

class Player():
    def __init__(self, inventory):
        self.health=100
        self.mana=100
        self.stamina=100
        self.inventory = inventory

    def use_potion(self):
        potion = self.inventory.get_potion()
        if potion:
            self.health += potion.varamount
            self.inventory.remove_potion()
        print("Used a ",potion.name," !")

inventory=Inventory()

healthpotion=Potion("Health potion", 50)
inventory.add_potion(healthpotion)

player=Player(inventory)
player.use_potion()

Comments

0
class Potion():
    def __init__(self,name,var,varamount):
        self.name=name
        self.var=var
        self.varamount=varamount

class Inventory():
    def __init__(self):
        self.items={}

    def add_item(self, item):
        if item in self.items.keys():
            self.items[item] += 1
        else:
            self.items[item] = 1
        print ('Added a {} potion!'.format(item.name)

    def remove_item(self, item):
        if item in self.items.keys():
            self.items[item] -= 1
            return True
        else:
            print ('No such {} exists!'.format(item.name))
            return False


class Player():
    def __init__(self):
        self.health=100
        self.mana=100
        self.stamina=100
        self.inventory = Inventory()

    def use_item(self, item):
        if isinstance(item, Potion):
            if self.inventory.remove_item(item):
                if item.var == 'health':
                    self.health += item.varamount
                    print ('Used a {0} and healed {1}!'.format(item.name, item.varamount))

player=Player()
healthpotion=Potion("Health potion", 'health', 50)
player.use_item(healthpotion)
player.inventory.add_item(healthpotion)
player.use_item(healthpotion)

#No such Health potion exists!
#Added a health potion!
#Used a Health potion and healed 50!

You need to think through the way your objects work first.

Does the inventory use the potion, or does the player use the potion?

In the code I provided, I made Player class have its own inventory. And then Player can use potion that was added into its own inventory.

5 Comments

I find this a weird solution... Player knows way too much: It can iterate over Inventory items (a behaviour that should be encapsulated in Inventory, and can differentiate different Items (which should be encapsulated in Item).
@NilsWerner It all depends on how the designer wishes to classify and assign functionality to the objects. In my example, I choose to make Player have an Inventory, because I am aware that other object classes, like Shop, Army, Monster, Bank can have Inventory. But not all of them will have health, so they might have different use_item functionalities. For example, a health potion might harm a Monster which is a demon etc
You must see that it will make Player incredibly complex, if it needs to know about all other classes and how to interact with them, though...
There's no right or wrong answer really. Like I said, its all about the design.
You should read up on the SOLID principle.

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.