Python类继承AttributeError-为什么?如何修复?

Python类继承AttributeError-为什么?如何修复?,python,class,inheritance,Python,Class,Inheritance,类似的问题包括:和。我还通读了我能找到的所有在线文档,但我还是很困惑。我非常感谢你的帮助 我想在我的CastSpell类lumus方法中使用Wand class.wandtype属性。但我一直收到错误“AttributeError:'CastSpell'对象没有属性'wandtype' 此代码适用于: class Wand(object): def __init__(self, wandtype, length): self.length = length

类似的问题包括:和。我还通读了我能找到的所有在线文档,但我还是很困惑。我非常感谢你的帮助

我想在我的CastSpell类lumus方法中使用Wand class.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() 
此代码尝试了继承,但没有

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() 

我尝试过使用super()方法,但没有效果。我非常感谢您帮助我理解a)为什么在这种情况下类继承不起作用,b)如何让它起作用

您需要调用超类的init方法。否则,wandtype和length永远不会在当前CastSpell实例上设置

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
或者,您可以在init方法之外的对象上添加类型和长度作为属性:

class Wand(object):
    wandtype = None
    length = None
然后,它们将始终可用(尽管在初始化之前它们的值为None)


然而,你确定CastSpell应该是Wand的一个子类吗?施咒是一种动作,听起来更像是一种魔杖法

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

简单地说,您可以在继承它的类中重写
Wand.\uuuu init\uuuu
,因此
CastSpell.wandtype
永远不会在
CastSpell
中设置。除此之外,
我的魔杖
无法将信息传递到
施法
,因此您对继承的作用感到困惑

无论您如何操作,您都必须以某种方式将
length
wandtype
传递给
castmail
。一种方法是将它们直接包含到
CastSpell中

class CastSpell(Wand):
    def __init__(self, spell, thing, length, wandtype):
        self.spell = spell 
        self.thing = thing
        self.length = length
        self.wandtype = wandtype
class CastSpell(Wand):
    def __init__(self, spell, thing, length, wandtype):
        self.spell = spell 
        self.thing = thing
        super(CastSpell, self).__init__(length, wandtype)
另一种更通用的方法是将这两个函数传递给基类的own
\uuuu init\uuuu()

另一种方法是停止使用
CastSpell
Wand
继承(是
CastSpell
一种
Wand
?还是一种
Wand
所做的事情?),而是让每根魔杖都能有一些
CastSpell
在里面:尝试一下,而不是“is-a”(a
CastSpell
是一种
Wand
)“has-a”(a
Wand
has
Spell
s)

这里有一个简单但不是很好的魔杖商店咒语:

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"
是的,
super()

Python中对超类的正常调用(不幸的是)是通过引用超类显式完成的

如果我正确地解释了你的问题,你会想知道为什么
.length
.wandtype
属性没有出现在
CastSpell
的实例中。这是因为没有调用Wand.init()方法。你应该这样做:

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

也就是说,你似乎没有正确地使用继承权。施咒是一种“动作”,而魔杖是一种“东西”“。对于继承来说,这并不是一个真正有意义的抽象。

CastSpill对象真的应该是'Wand'对象吗?我只是想获得.wandtype属性,这就是我使用它的原因。”。我知道,这听起来有点奇怪。为什么不让一个
拼写
类和一个
施法
方法,简单地把魔杖类型作为参数呢?这很有意义D谢谢你的建议。不过,就继承而言,我似乎完全被搞糊涂了,所以下面的答案非常有用。根据您的需要,您可以有一个
PhoenixFeatherWand
类、一个
Lumus
类、一个
WingardiumLeviosa
类,在一种典型的面向对象语言中,你可能会让它们继承自
魔杖
拼写
类,但由于python是鸭子类型的语言,你可以让它们定义相同的接口,比如
cast
方法、
大小
属性、
名称
属性等等。我确实很困惑,但是这有帮助,所以谢谢。是否有任何方法可以完成我试图使用类继承所做的事情?当然,请参阅编辑。现在我将展示如何让魔杖拥有咒语:)谢谢!如果我使用你的第二个例子,我真的不需要创建魔杖类,这是否准确?看起来有点多余……不,你们仍然需要魔杖,因为它有“fulldesc”。当然,您可以将其移动到CastSpell并完全去掉魔杖,但想象一下您希望使用不同法术的不同魔杖:魔杖类允许您对每根魔杖进行建模,因此它可能很有用。如果你只关心咒语和施法,魔杖确实是多余的。对不起,我删除了这样做的代码:在
Wand.addspell
中,我有一行类似于
spell.wandtype=self.wandtype
。这让魔咒知道它在哪根魔杖里。。。但有一个问题:这样你只能在一根魔杖上施咒语!现在我们在
cast
ing时传递wandtype。类的
\uu repr\uu()
告诉您如何显示该类(例如:
打印我的魔杖。拼写
打印lumus
)。您可以自定义它以显示所需的确切信息,
返回self.name
使其显示名称。删除
\uuuuu repr\uuuuuu
方法,然后尝试
打印我的魔杖。拼写
以查看默认显示。正如文章所指出的,
super
可以使用,如果您一致使用,并且只使用关键字参数。他没有使用关键字参数。他的方法参数对于不同的
\uuuu init\uu
函数有不同的含义。这对于
super()
是完全不合适的。这是事实。然而,他显然必须澄清当前设计中的一些问题,虽然继承可能与他的需求无关,但如果他想让
CastSpell
方法起作用,他可以通过使用更多参数来修改初始值设定项以使用它。在我看来,
CastSpell.\uuuuu init\uuuuu
Wand选择默认参数似乎很奇怪