Similar questions on SO include: this one and this. I've also read through all the online documentation I can find, but I'm still quite confused. I'd be grateful for your help.
I want to use the Wand class .wandtype attribute in my CastSpell class lumus method. But I keep getting the error "AttributeError: 'CastSpell' object has no attribute 'wandtype'."
This code works:
class Wand(object):def __init__(self, wandtype, length):self.length = length self.wandtype = wandtypedef fulldesc(self):print "This is a %s wand and it is a %s long" % (self.wandtype, self.length) class CastSpell(object):def __init__(self, spell, thing):self.spell = spell self.thing = thingdef lumus(self):print "You cast the spell %s with your wand at %s" %(self.spell, self.thing) def wingardium_leviosa(self): print "You cast the levitation spell."my_wand = Wand('Phoenix-feather', '12 inches')
cast_spell = CastSpell('lumus', 'door')
my_wand.fulldesc()
cast_spell.lumus()
This code, with attempted inheritance, doesn't.
class Wand(object):def __init__(self, wandtype, length):self.length = length self.wandtype = wandtypedef fulldesc(self):print "This is a %s wand and it is a %s long" % (self.wandtype, self.length) class CastSpell(Wand):def __init__(self, spell, thing):self.spell = spell self.thing = thingdef lumus(self):print "You cast the spell %s with your %s wand at %s" %(self.spell, self.wandtype, self.thing) #This line causes the AttributeError! print "The room lights up."def wingardium_leviosa(self): print "You cast the levitation spell."my_wand = Wand('Phoenix-feather', '12 inches')
cast_spell = CastSpell('lumus', 'door')
my_wand.fulldesc()
cast_spell.lumus()
I've tried using the super() method to no avail. I'd really appreciate your help understanding a) why class inheritance isn't working in this case, b) how to get it to work.
To put it simply, you override Wand.__init__
in the class that inherits from it, so CastSpell.wandtype
is never set in CastSpell
. Besides that, my_wand
can't pass information into cast_spell
, so you're confused about the role of inheritance.
Regardless of how you do it, you have to somehow pass length
and wandtype
to CastSpell
. One way would be to include them directly into CastSpell.__init__
:
class CastSpell(Wand):def __init__(self, spell, thing, length, wandtype):self.spell = spell self.thing = thingself.length = lengthself.wandtype = wandtype
Another, more generic way would be to pass these two to the base class' own __init__()
:
class CastSpell(Wand):def __init__(self, spell, thing, length, wandtype):self.spell = spell self.thing = thingsuper(CastSpell, self).__init__(length, wandtype)
Another way would be to stop making CastSpell
inherit from Wand
(is CastSpell
a kind of Wand
? or something a Wand
does?) and instead make each Wand be able to have some CastSpell
s in it: instead of "is-a" (a CastSpell
is a kind of Wand
), try "has-a" (a Wand
has Spell
s).
Here's a simple, not so great way to have a Wand store spells:
class Wand(object):def __init__(self, wandtype, length):self.length = lengthself.wandtype = wandtypeself.spells = {} # Our container for spells. # You can add directly too: my_wand.spells['accio'] = Spell("aguamenti", "fire")def fulldesc(self):print "This is a %s wand and it is a %s long" % (self.wandtype, self.length)def addspell(self, spell):self.spells[spell.name] = spelldef cast(self, spellname):"""Check if requested spell exists, then call its "cast" method if it does."""if spellname in self.spells: # Check existence by namespell = self.spells[spellname] # Retrieve spell that was added before, name it "spell"spell.cast(self.wandtype) # Call that spell's cast method, passing wandtype as argumentelse:print "This wand doesn't have the %s spell." % spellnameprint "Available spells:"print "\n".join(sorted(self.spells.keys()))class Spell(object):def __init__(self, name, target):self.name = nameself.target = targetdef cast(self, wandtype=""):print "You cast the spell %s with your %s wand at %s." % (self.name, wandtype, self.target)if self.name == "lumus":print "The room lights up."elif self.name == "wingardium leviosa":print "You cast the levitation spell.",print "The %s starts to float!" % self.targetdef __repr__(self):return self.namemy_wand = Wand('Phoenix-feather', '12 inches')
lumus = Spell('lumus', 'door')
wingardium = Spell("wingardium leviosa", "enemy")my_wand.fulldesc()
lumus.cast() # Not from a Wand! I.e., we're calling Spell.cast directly
print "\n\n"my_wand.addspell(lumus) # Same as my_wand.spells["lumus"] = lumus
my_wand.addspell(wingardium)
print "\n\n"my_wand.cast("lumus") # Same as my_wand.spells["lumus"].cast(my_wand.wandtype)
print "\n\n"
my_wand.cast("wingardium leviosa")
print "\n\n"
my_wand.cast("avada kadavra") # The check in Wand.cast fails, print spell list instead
print "\n\n"