Jamey Phillips Jamey Phillips - 7 months ago 10
Python Question

Python AttributeError: type object 'x' has no attribute 'x'

I'm currently working on a simple text-based game in Python just to practice python and object-oriented programming but I'm running into this error where it tells me that 'LargeManaPotion' has no attribute 'name' when I can see that it does, and it is declared the exact same way as 'SmallManaPotion' which works just fine. I'm assuming it's some stupid mistake that I'm just overlooking or something but would appreciate the help. Also, the program will print the potion just fine when I print the inventory of the player in the player.inventory function so I'm not sure why it doesn't work with within the trade function. Anyways, here is the relevant code. Thanks in advance.

class ManaPotion:
def __init__(self):
raise NotImplementedError("Do not create raw ManaPotion objects.")

def __str__(self):
return "{} (+{} Mana)".format(self.name, self.mana_value)


class LargeManaPotion(ManaPotion):
def __init__(self):
self.name = "Large Mana Potion"
self.mana_value = 45
self.value = 40


class SmallManaPotion(ManaPotion):
def __init__(self):
self.name = "Small Mana Potion"
self.mana_value = 15
self.value = 10


As you can see it is identical to the SmallManaPotion.
Here is the function which causes the error.

class TraderTile(MapTile):
def intro_text(self):
return "A frail not-quite-human, not-quite-creature squats in the corner " \
"\nclinking his gold coins together. \nHe looks willing to trade."

def __init__(self, x, y):
self.trader = npc.Trader()
super().__init__(x, y)

def trade(self, buyer, seller):
for i, item in enumerate(seller.inventory, 1):
#the line below here is where I'm getting the error.
print("{}. {} - {} Gold".format(i, item.name, item.value))
while True:
user_input = input("Choose an item or press Q to exit: ")
if user_input in ['q', 'Q']:
return
else:
try:
choice = int(user_input)
to_swap = seller.inventory[choice - 1]
self.swap(seller, buyer, to_swap)
except ValueError:
print("Invalid choice!")

def swap(self, seller, buyer, item):
if item.value > buyer.gold:
print("That's too expensive.")
return
seller.inventory.remove(item)
buyer.inventory.append(item)
seller.gold = seller.gold + item.value
buyer.gold = buyer.gold - item.value
print("Trade complete!")

def check_if_trade(self, player):
while True:
print("\n\nGold: {} \nWould you like to (B)uy, (S)ell, or (Q)uit?".format(player.gold))
user_input = input()
if user_input in ['Q', 'q']:
return
elif user_input in ['B', 'b']:
print("\n\nGold: {} \nHere's whats available to buy: ".format(player.gold))
self.trade(buyer=player, seller=self.trader)
elif user_input in ['S', 's']:
print("\n\nGold: {} \nHere's what's available to sell: ".format(player.gold))
self.trade(buyer=self.trader, seller=player)
else:
print("Invalid choice!")


However, this function calls LargeManaPotion but without any errors.

def print_inventory(self):
print("Inventory:")
for item in self.inventory:
print('* ' + str(item))
print("* Gold: {}".format(self.gold))
best_weapon = self.most_powerful_weapon()
print("Your best weapon is your {}".format(best_weapon))


Error and stacktrace:

Choose an action:
i: Print inventory
t: Trade
n: Go north
s: Go south
w: Go west
m: Replenish Mana
Action: t


Gold: 33
Would you like to (B)uy, (S)ell, or (Q)uit?
>>>b

Gold: 33
Here's whats available to buy:
1. Crusty Bread - 12 Gold
2. Crusty Bread - 12 Gold
3. Crusty Bread - 12 Gold
4. Healing Potion - 60 Gold
5. Healing Potion - 60 Gold
6. Small Mana Potion - 10 Gold
7. Small Mana Potion - 10 Gold

Traceback (most recent call last):

File "/Users/Cpt_Chirp/Documents/Escape/game.py", line 74, in <module>
play()

File "/Users/Cpt_Chirp/Documents/Escape/game.py", line 17, in play
choose_action(room, player)

File "/Users/Cpt_Chirp/Documents/Escape/game.py", line 30, in choose_action
action()

File "/Users/Cpt_Chirp/Documents/Escape/player.py", line 112, in trade
room.check_if_trade(self)

File "/Users/Cpt_Chirp/Documents/Escape/world.py", line 127, in check_if_trade
self.trade(buyer=player, seller=self.trader)

File "/Users/Cpt_Chirp/Documents/Escape/world.py", line 96, in trade
print("{}. {} - {} Gold".format(i, item.name, item.value))
AttributeError: type object 'LargeManaPotion' has no attribute 'name'

Process finished with exit code 1

Answer

I don't believe you have provided the correct code, but you have provided enough to determine what's going on here

a = list()
b = list
a.append(1)
b.append(1)

Which one of these will raise an error? Obviously, the append to b. While objects of type list of a method append, the base class "Type List" does not.

Somewhere, you have assigned the type LargeManaPotion to a variable and attempted to access the field name from it. But the type itself does not have those fields. The reason you can do this is because in python, classes are first class objects and can be passed around like any other objects


Let's looking at something closer to your live code

class Pot(object):
    def add():pass

pots = [Pot(), Pot(), Pot(), Pot(), Pot]
for pot in pots: pots.add()

Now where is the problem? They are all instances of list, are they not? Why does only the last one raise an AttributeError?

Of course, because they are not all the same. The first 4 items are instances of the class Pot. The are returned from the method __new__, defined in the class type Pot which is invoked when I use that "parentheses notation" after the variable name. At runtime, python has no idea what the variable "Pot" is. It happens to be a type variable, who's invocation generates an instance object.

The last item is an instance of the class "type Pot". It is not a Pot. It is a type. It's __class__ attribute is not Pot. It's __class__ attribute is type Types are used to generate instances. it is meaningless to "add" to a type.


Let's say you had potions in real life. You can do things with potions. You can drink them. You can check their boiling points (if they have a tag, or maybe through science).

Instead, let's say you had the recipe for a potion lying around. And you said: "drink the recipe". "What's the recipe's boiling point". The universe is responding: "that's undefined". You meant to look at a potion. Instead you looked at its recipe. Like all OO metaphors, this one is incomplete. Additional reading:

Comments