Home > OS >  Use exec to modify global variables in a class
Use exec to modify global variables in a class

Time:03-09

I've recently been refactoring some of my code to use OOP, and I've run into a problem where I can't quite get either global vars, exec(), or a combination of the two to work. The relevant code is below:

# invObject class. Has all properties of an inventory object.
class invObject:
    def __init__(self, name, info, output, effect):
        self.name = name # Used in menus.
        self.info = info # Describes effect.
        self.output = output # Printed on use.
        self.effect = effect # Executed on use.

    def printInfo(self): # Function for name and description.
        return "{} - {}".format(self.name, self.info)

    def use(self): # Function to use items. It's that easy.
        global dodgeChance
        global maxHp
        global hp
        global atk
        exec(self.effect)
        print(self.output) # Prints output. Also very simple.
        print("{} {} {} {}".format(dodgeChance, maxHp, hp, atk)) # debugging
...

inventory[slot].use() # does not update values

Basic rundown: inventory[slot].use() should call the use() function of the object. use() should execute the code stored in inventory[slot].effect.

The output from the debugging line doesn't change anything, even inside the function. I've already tried making it return exec(self.effect) to no avail. print(self.output) does work.

EDIT: Here's a minimal reproducible example that includes everything it needs to run, not just the most important things.

# Assign base stats
dodgeChance = 0
maxHp = int(input("Input maximum HP. > "))
hp = int(input("Input current HP. > "))

# invObject class. Has all properties of an inventory object.
class invObject:
    def __init__(self, name, info, output, effect):
        self.name = name # Used in menus.
        self.info = info # Describes effect.
        self.output = output # Printed on use.
        self.effect = effect # Executed on use.

    def printInfo(self): # Function for name and description.
        return "{} - {}".format(self.name, self.info)

    def use(self): # Function to use items. It's that easy.
        global dodgeChance
        global maxHp
        global hp
        global atk
        exec(self.effect)
        print(self.output) # Prints output. Also very simple.
        print("{} {} {} {}".format(dodgeChance, maxHp, hp, atk)) # debugging

empty = invObject("None", "Vacant slot.", "There's nothing in that slot!", "")
apple = invObject("Apple", "Gives 20 health.", "Ate the apple. Gained 20 health.", "hp = hp   20\nif hp > maxHp: hp = maxHp")
drink = invObject("Drink", "Some kind of energy drink. Raises dodge chance to 75%.", "Drank the drink. Dodge chance is now 75%!", "dodgeChance = 75")

# Assign base inventory
inventory = [apple, drink, empty]

slot = int(input("Input slot number to use. ")) - 1
inventory[slot].use() # does not update values

# Show final stats
print("New HP value: "   str(hp))
print("Dodge chance: "   str(dodgeChance)   "%")
print()
print("Inventory contents:")
print("Slot 1: "   str(inventory[0].name))
print("Slot 2: "   str(inventory[1].name))
print("Slot 3: "   str(inventory[2].name))

EDIT 2: Another thing: the code works if I don't use exec() (e.g. change it out for hp = 20).

CodePudding user response:

exec() has optional arguments for you to provide the global and local variable contexts.

But you didn't provide them.

  • Related