2012-05-20 14 views
6

एसओ पर इसी तरह के प्रश्नों में शामिल हैं: this one और this। मैंने उन सभी ऑनलाइन दस्तावेजों के माध्यम से भी पढ़ा है जिन्हें मैं पा सकता हूं, लेकिन मैं अभी भी काफी उलझन में हूं। मैं आपकी मदद के लिए आभारी रहूंगा।पायथन कक्षा विरासत विशेषताएँ त्रुटि - क्यों? कैसे ठीक करना है?

मैं अपने कास्टस्पेल क्लास लुमस विधि में वंड क्लास। 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() 

मैंने सुपर() विधि का उपयोग करने का कोई फायदा नहीं लिया है। मैं वास्तव में आपकी मदद की सराहना करता हूं ए) इस मामले में कक्षा विरासत क्यों काम नहीं कर रही है, बी) इसे कैसे काम पर लाया जाए।

+1

क्या 'CastSpell' ऑब्जेक्ट वास्तव में * एक 'वंड' ऑब्जेक्ट होना चाहिए? – Darthfett

+0

मैं बस .wandtype विशेषता प्राप्त करना चाहता था, यही कारण है कि मैंने इसका उपयोग किया है। यह थोड़ा अजीब लगता है, मुझे पता है। – user1186742

+1

क्यों 'वर्तनी' विधि के साथ 'वर्तनी' श्रेणी नहीं है, जो कि केवल वंड प्रकार को तर्क के रूप में लेता है? – Darthfett

उत्तर

6

कहें यह बस, आप वर्ग है कि यह से विरासत में Wand.__init__ ओवरराइड, तो CastSpell.wandtypeCastSpell में सेट कभी नहीं किया गया है। इसके अलावा, my_wandcast_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 

एक और, और अधिक सामान्य तरीके से आधार वर्ग की अपनी __init__() करने के लिए इन दो पारित करने के लिए होगा:

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

एक और तरीका है को रोकने के लिए किया जाएगा Wand से CastSpell इनहेरिट बनाने (? CastSpellWand का एक प्रकार या कुछ और एक Wand करता है?) और बदले बनाने के प्रत्येक वैंड इसमें कुछ CastSpell रों है करने में सक्षम हो: के बजाय "है-एक" (एक CastSpellWand की तरह है), प्रयत्न "है-ए" (Wand में Spell एस है)।

यहाँ एक वैंड की दुकान के लिए एक सरल, नहीं तो शानदार तरीका मंत्र है:

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" 
+0

मैं वास्तव में उलझन में हूं, लेकिन इससे मदद मिलती है, इसलिए धन्यवाद। क्या कक्षा उत्तराधिकारी का उपयोग करने के लिए मैं क्या करने की कोशिश कर रहा हूं? – user1186742

+0

निश्चित रूप से, संपादन देखें। अब मैं दिखाऊंगा कि आप कैसे वांड को कास्टस्पेल बना सकते हैं :) – TryPyPy

+0

धन्यवाद! क्या यह सही है कि अगर मैं आपके दूसरे उदाहरण का उपयोग करना चाहता हूं तो मुझे वास्तव में एक वंड क्लास बनाने की आवश्यकता नहीं होगी? यह थोड़ा अनावश्यक लगता है ... – user1186742

1

आपको सुपरक्लास की इनिट विधि को कॉल करने की आवश्यकता है। अन्यथा, वर्तमान CastSpell उदाहरण पर wandtype और लंबाई कभी सेट नहीं हो। तब

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

, वे हमेशा उपलब्ध हो जाएगा (हालांकि वे जब तक कोई नहीं के एक मूल्य होगा:

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 और लंबाई विशेषताओं के रूप में वस्तु पर init विधि के बाहर जोड़ सकता है उन्हें शुरू किया गया है)।


हालांकि, क्या आप सुनिश्चित हैं कि कास्टस्पेल वंड का उप-वर्ग होना चाहिए? CastSpell एक क्रिया है, जो लगता है जैसे यह वंड का एक तरीका होना चाहिए।

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

इस उत्तर के लिए धन्यवाद। मुझे एक नाम त्रुटि मिलती है: जब मैं पहले समाधान को लागू करने का प्रयास करता हूं तो वैश्विक नाम 'wandtype' को परिभाषित त्रुटि नहीं होती है। इसके बजाय एक cast_spell विधि बनाने के रूप में बहुत अच्छी बात है। धन्यवाद। – user1186742

0

हाँ, super() नहीं है तुम क्या चाहते। क्यों नहीं, विवरण के लिए this article का संदर्भ लें।

पायथन में सुपरक्लास के लिए सामान्य कॉल (दुर्भाग्य से) सुपरक्लास का जिक्र करते हुए स्पष्ट रूप से किया जाता है।

मैं आपके सवाल का सही व्याख्या कर रहा हूँ, तो आप सोच रहे हैं कि क्यों .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. 

ऐसा कहा जाता है कि आप विरासत अधिकार का उपयोग नहीं कर रहे हैं। कास्टस्पेल एक "एक्शन" है जबकि वांड एक "चीज" है। यह वास्तव में एक अमूर्त नहीं है जो विरासत के लिए अच्छी समझ में आता है।

+1

जैसा कि लेख बताता है, 'सुपर' उपयोग करने के लिए ठीक है आप इसे लगातार उपयोग करते हैं, और केवल कीवर्ड तर्क का उपयोग करते हैं। – Darthfett

+0

वह कीवर्ड तर्क का उपयोग नहीं कर रहा है। उनके विधि तर्कों के अलग-अलग '__init__' कार्यों के लिए अलग-अलग अर्थ हैं। यह 'सुपर() 'के लिए पूरी तरह अनुचित है। –

+2

यह सच है। हालांकि, उन्हें स्पष्ट रूप से वर्तमान डिजाइन के साथ कुछ स्पष्ट करना है, और जबकि विरासत शायद उनकी जरूरतों के अनुरूप नहीं है, अगर वह 'कास्टस्पेल' विधि का काम करना चाहता था, तो वह अपने शुरुआती लोगों को अधिक तर्क लेकर इसका उपयोग करने के लिए प्रेरित कर सकता था । आईएमओ, 'Wand.__ init__' के लिए डिफ़ॉल्ट तर्क लेने के लिए' CastSpell .__ init__' के लिए अजीब लगता है, और उपयोगकर्ता को इसे अनुकूलित करने की अनुमति नहीं देता है। – Darthfett

संबंधित मुद्दे