Python class inheritance AttributeError - why? how to fix?

Similar questions on SO include: this and this . I also read all the online documentation I can find, but I'm still pretty confused. I would be grateful for your help.

I want to use the Wand attribute of the Wandtype class in my lumus method of the CastSpell class. But I keep getting the error "AttributeError: CastSpell object" does not have the "wandtype" attribute. "

This code works:

class Wand(object): def __init__(self, wandtype, length): self.length = length self.wandtype = wandtype def 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 = thing def 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 inheritance attempt code does not work.

 class Wand(object): def __init__(self, wandtype, length): self.length = length self.wandtype = wandtype def 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 = thing def 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 tried using the super () method to no avail. I would really appreciate your help in understanding a) why class inheritance does not work in this case, b) how to make it work.

+6
source share
3 answers

Simply put, you override Wand.__init__ in a class that inherits from it, so CastSpell.wandtype never installed in CastSpell . In addition, my_wand cannot pass information to cast_spell , so you are confused about the role of inheritance.

No matter how you do it, you need to somehow go through length and wandtype to CastSpell . One way is to include them directly in CastSpell.__init__ :

 class CastSpell(Wand): def __init__(self, spell, thing, length, wandtype): self.spell = spell self.thing = thing self.length = length self.wandtype = wandtype 

Another, more general way would be to pass these two into the base __init__() native class:

 class CastSpell(Wand): def __init__(self, spell, thing, length, wandtype): self.spell = spell self.thing = thing super(CastSpell, self).__init__(length, wandtype) 

Another way would be to stop CastSpell inheritance from Wand (is CastSpell a kind of Wand ? Or something a Wand ?) And instead make each Wand have the ability to have CastSpell 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-good way to have Wand stock spells:

 class Wand(object): def __init__(self, wandtype, length): self.length = length self.wandtype = wandtype self.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] = spell def cast(self, spellname): """Check if requested spell exists, then call its "cast" method if it does.""" if spellname in self.spells: # Check existence by name spell = self.spells[spellname] # Retrieve spell that was added before, name it "spell" spell.cast(self.wandtype) # Call that spell cast method, passing wandtype as argument else: print "This wand doesn't have the %s spell." % spellname print "Available spells:" print "\n".join(sorted(self.spells.keys())) class Spell(object): def __init__(self, name, target): self.name = name self.target = target def 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.target def __repr__(self): return self.name my_wand = Wand('Phoenix-feather', '12 inches') lumus = Spell('lumus', 'door') wingardium = Spell("wingardium leviosa", "enemy") my_wand.fulldesc() lumus.cast() # Not from a Wand! Ie, 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" 
+6
source

You need to call the init superclass method. Otherwise, wandtype and length will never be set in the current CastSpell instance.

 class CastSpell(Wand): def __init__(self, spell, thing): super(CastSpell, self).__init__(A, B) # A, B are your values for wandtype and length self.spell = spell self.thing = thing 

Alternatively, you can add wandtype and length as attributes of an object outside the init method:

 class Wand(object): wandtype = None length = None 

Then they will always be available (although they will be None until they are initialized).


However, are you sure CastSpell should be a subclass of Wand? CastSpell is an action that sounds more like a Wand method.

 class Wand(object): [...] def cast_spell(self, spell, thing): [etc.] 
+1
source

Yes, super() not what you want. See this article for details on why not.

Normal Python superclass calls (unfortunately) are made explicitly, referencing the superclass.

If I interpret your question correctly, you are wondering why the .length and .wandtype not displayed in CastSpell instances. This is because the Wand method. init () is not called. You should do it as follows:

 class CastSpell(Wand): def __init__(self, spell, thing): Wand.__init__(self, whateverdefaultvalue_youwantforwandtype, default_value_for_length) self.spell = spell etc. 

However, you do not seem to be using inheritance rights. CastSpell is β€œaction,” and wand is β€œthing.” This is not an abstraction that makes sense for inheritance.

0
source

Source: https://habr.com/ru/post/916179/


All Articles