Атрибут Наследования классов Python - почему? как исправить?

Подобные вопросы по SO включают в себя:этот а такжеэтот, Я также прочитал всю онлайновую документацию, которую смог найти, но я все еще в замешательстве. Я был бы благодарен за вашу помощь.

Я хочу использовать атрибут Wand класса .wandtype в моем методе класса CastSpell lumus. Но я продолжаю получать сообщение об ошибке "AttributeError:" CastSpell & apos; У объекта нет атрибута "wandtype". & quot;

Этот код работает:

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 (), но безрезультатно. Я очень ценю вашу помощь в понимании а) почему наследование классов не работает в этом случае, б) как заставить его работать.

 user118674220 мая 2012 г., 03:24
Я просто хотел получить атрибут .wandtype, поэтому я использовал это. Это звучит немного странно, я знаю.
 user118674220 мая 2012 г., 03:29
Это имело бы много смысла. : D Спасибо за предложение. Похоже, что я полностью запутался в том, что касается наследования, поэтому ответы ниже весьма полезны.
 Darthfett20 мая 2012 г., 03:35
В зависимости от ваших потребностей, вы можете иметьPhoenixFeatherWand класс, аLumus класс, аWingardiumLeviosa класс и т. д. В типичном объектно-ориентированном языке они могут наследоваться отWand или жеSpell класс, но с Python, являющимся языком с утиным типом, вы можете просто дать им определить тот же интерфейс, такой какcast метод,size атрибут,name атрибут и т. д.
 Darthfett20 мая 2012 г., 03:27
Почему бы не иметьSpell класс сcast метод, который просто принимает тип палочки в качестве аргумента?
 Darthfett20 мая 2012 г., 03:23
Должен ли «CastSpell»? объект действительноbe «жезл»; объект?

Ответы на вопрос(3)

super() это не то, что вы хотите. Ссылаться наЭта статья для деталей о том, почему нет.

Обычные вызовы суперкласса в Python (к сожалению) делаются явно, ссылаясь на суперкласс.

Если я правильно понимаю ваш вопрос, вам интересно, почему.length а также.wandtype атрибуты не в порядке, в случаяхCastSpell, Это потому что палочка.init() метод не вызывается. Вы должны сделать это так:

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

Тем не менее, вы, похоже, не используете право наследования. CastSpell - это «действие» в то время как палочка - это «вещь». Это на самом деле не абстракция, которая имеет смысл для наследования.

 20 мая 2012 г., 06:11
@thepaul был не мной, но, возможно, downvoter думал, что ваше первое предложение может быть неправильно истолковано. Технически,super точно решает проблему, хотя это вызывает другой внешний интерфейс. Upvote от меня за ссылку, просто потому, что это объясняет хорошее использование супер. : P @ user1186742 Это можно легко исправить, добавив аргументы в конструктор, но тогда он действует так же, какsuper, передав все аргументы суперклассу.
 20 мая 2012 г., 03:36
Он не использует ключевые аргументы. Его аргументы метода имеют разные значения для разных__init__ функции. Это совершенно неуместно дляsuper().
 20 мая 2012 г., 03:40
Это правда. Однако он явно должен кое-что прояснить с текущим дизайном, и, хотя наследование, вероятно, не соответствует его потребностям, если он хочет сделатьCastSpell метод работы, он мог изменить его инициализаторы, чтобы использовать его, принимая больше аргументов. ИМО, кажется странным дляCastSpell.__init__ выбрать аргументы по умолчанию дляWand.__init__и не позволяет пользователю настроить это.
 20 мая 2012 г., 03:50
Шутки в сторону? Недостаток?
 20 мая 2012 г., 03:26
Как указывается в статье,super Это нормально использовать, если вы используете его последовательно, и использовать только ключевые аргументы.

wandtype и длина никогда не устанавливаются в текущем экземпляре 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

В качестве альтернативы вы можете добавить wandtype и length в качестве атрибутов на объект вне метода init:

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

Затем они всегда будут доступны (хотя они будут иметь значение None до тех пор, пока они не будут инициализированы).

Тем не менее, вы уверены, что CastSpell должен быть подклассом Wand? CastSpell - это действие, которое звучит так, будто это должен быть метод Wand.

class Wand(object):
    [...]
    def cast_spell(self, spell, thing):
         [etc.]
 user118674220 мая 2012 г., 03:31
Спасибо за этот ответ. Я получаю NameError: глобальное имя "wandtype" не определена ошибка при попытке реализовать первое решение. Очень хороший момент, поскольку вместо этого создается метод cast_spell. Благодарю.
Решение Вопроса

Wand.__init__ в классе, который наследует от него, такCastSpell.wandtype никогда не устанавливается вCastSpell, Кроме того,my_wand не может передавать информацию вcast_spellТаким образом, вы не уверены в роли наследования.

Независимо от того, как вы это делаете, вы должны как-то пройтиlength а такжеwandtype вCastSpell, Одним из способов было бы включить их непосредственно вCastSpell.__init__:

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

Другой, более общий способ - передать эти два значения базовому классу & apos; своя__init__():

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

Другим способом было бы прекратить делатьCastSpell наследовать отWand (являетсяCastSpell типаWand? или что-тоWand делает?) и вместо этого сделать каждую палочку иметь возможность иметь некоторыеCastSpells в нем: вместо "is-a" (аCastSpell это своего родаWand) попробуйте & quot; has-a & quot; (аWand имеетSpellс).

Вот простой, но не очень удачный способ иметь заклинания магазина Wand:

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"
 user118674220 мая 2012 г., 03:54
Спасибо! Верно ли, что мне действительно не нужно было бы создавать класс Wand, если бы я использовал ваш второй пример? Кажется, немного излишним ...
 user118674220 мая 2012 г., 03:23
Я действительно в замешательстве, но это помогает, так что спасибо. Есть ли способ выполнить то, что я пытаюсь сделать, используя наследование классов?
 20 мая 2012 г., 03:30
Конечно, см. Редактировать. Теперь я покажу, как можно заставить Wand использовать CastSpells :)
 20 мая 2012 г., 03:59
Нет, вам все еще нужен Wand, потому что у него был "fulldesc". Конечно, вы можете переместить это в CastSpell и полностью избавиться от жезла, но представьте, что вы хотите иметь разные жезлы с разными заклинаниями: класс жезлов позволяет вам моделировать каждую жезл, поэтому он может быть полезен. Если вам небезразличны только заклинания и их наложение, то палочка действительно лишняя.
 20 мая 2012 г., 04:20
Извините, я удалил код, который сделал это: вWand.addspellУ меня была такая строчкаspell.wandtype = self.wandtype, Так что это заставило заклинание узнать, в какой это волшебной палочке ... но возникла проблема: таким способом вы могли бы иметь заклинание только в одной волшебной палочке! Итак, теперь мы передаем тип палочки, когдаcastING.__repr__() класса говорит вам, как отобразить этот класс (например:print my_wand.spells или жеprint lumus). Вы можете настроить его, чтобы показать точную информацию, которую вы хотите,return self.name заставляет его показывать имя Удалить__repr__ метод и попытатьсяprint my_wand.spells чтобы увидеть дисплей по умолчанию.

Ваш ответ на вопрос