Python类继承AttributeError - 为什么?怎么修?

use*_*742 6 python inheritance class

关于SO的类似问题包括:这个这个.我还阅读了我能找到的所有在线文档,但我仍然很困惑.我很感激你的帮助.

我想在CastSpell类lumus方法中使用Wand类.wandtype属性.但我不断收到错误"AttributeError:'CastSpell'对象没有属性'wandtype'."

此代码有效:

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() 
Run Code Online (Sandbox Code Playgroud)

此代码尝试继承,但没有.

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() 
Run Code Online (Sandbox Code Playgroud)

我尝试使用super()方法无济于事.我非常感谢你帮助理解a)为什么类继承在这种情况下不起作用,b)如何使它工作.

Try*_*yPy 7

简单地说,你Wand.__init__在从它继承的类中重写,因此CastSpell.wandtype永远不会设置CastSpell.除此之外,my_wand无法传递信息cast_spell,因此您对继承的作用感到困惑.

不管你怎么做,你必须以某种方式传递lengthwandtypeCastSpell.一种方法是将它们直接包含在CastSpell.__init__:

class CastSpell(Wand):
    def __init__(self, spell, thing, length, wandtype):
        self.spell = spell 
        self.thing = thing
        self.length = length
        self.wandtype = wandtype
Run Code Online (Sandbox Code Playgroud)

另一种更通用的方法是将这两个传递给基类'自己的__init__():

class CastSpell(Wand):
    def __init__(self, spell, thing, length, wandtype):
        self.spell = spell 
        self.thing = thing
        super(CastSpell, self).__init__(length, wandtype)
Run Code Online (Sandbox Code Playgroud)

另一种方法是停止CastSpell继承Wand(是CastSpell一种Wand?或某种东西Wand?)而是让每个魔杖都能够有一些CastSpells:而不是"is-a"(a CastSpell是一种Wand),尝试"has-a"(a Wandhas 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's 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! 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"
Run Code Online (Sandbox Code Playgroud)