2012-03-18 21 views
18

से अभिभावक वर्ग विशेषता तक पहुंच प्राप्त करने के लिए मेरे पास कक्षाकक्षा वर्ग my_list है। मैं इसके बारे में एक उपवर्ग SubKlass, जिसमें मैं एक वर्ग विशेषता my_list माता पिता वर्ग से एक ही विशेषता का एक संशोधित संस्करण है जो करना चाहते हैं:उप-वर्ग निकाय

class Klass(): 
    my_list = [1, 2, 3] 


class SubKlass(Klass): 
    my_list = Klass.my_list + [4, 5] # this works, but i must specify parent class explicitly 
    #my_list = super().my_list + [4, 5] # SystemError: super(): __class__ cell not found 
    #my_list = my_list + [4, 5] # NameError: name 'my_list' is not defined 


print(Klass.my_list) 
print(SubKlass.my_list) 

तो, वहाँ के बिना माता पिता के वर्ग विशेषता का उपयोग करने के लिए एक रास्ता है इसका नाम निर्दिष्ट कर रहे हैं?

अद्यतन: http://bugs.python.org/issue11339:

अजगर समस्या ट्रैकर पर एक बग नहीं है। आइए आशा करते हैं कि यह किसी बिंदु पर solved होगा।

उत्तर

10

आप नहीं कर सकते।

पायथन में एक वर्ग परिभाषा कार्य निम्नानुसार काम करता है।

  1. दुभाषिया class कथन को कोड के ब्लॉक के बाद देखता है।

  2. यह एक नया नामस्थान बनाता है और नामस्थान में उस कोड को निष्पादित करता है।

  3. यह परिणामस्वरूप नामस्थान, कक्षा का नाम, आधार वर्ग, और मेटाक्लास (यदि लागू हो) के साथ type निर्मित है।

  4. यह परिणाम कक्षा के नाम पर निर्दिष्ट करता है।

कक्षा परिभाषा के अंदर कोड चलाते समय, आप नहीं जानते कि बेस क्लास क्या हैं, इसलिए आप उनके गुण नहीं प्राप्त कर सकते हैं।

आप कर सकते हैं इसे परिभाषित करने के तुरंत बाद कक्षा को संशोधित कर सकते हैं।


संपादित करें: यहां एक छोटा वर्ग सजावट है जिसका उपयोग आप विशेषता को अद्यतन करने के लिए कर सकते हैं। विचार यह है कि आप इसे एक नाम और एक समारोह देते हैं। यह आपकी कक्षा के सभी मूल वर्गों को देखता है, और उस नाम के साथ उनके गुण प्राप्त करता है। फिर यह फ़ंक्शन को बेस क्लास से प्राप्त मानों की सूची और उप-वर्ग में परिभाषित मान की सूची के साथ कॉल करता है। इस कॉल का परिणाम नाम से जुड़ा हुआ है।

कोड अधिक मतलब हो सकता है:

>>> def inherit_attribute(name, f): 
...  def decorator(cls): 
...    old_value = getattr(cls, name) 
...    new_value = f([getattr(base, name) for base in cls.__bases__], old_value) 
...    setattr(cls, name, new_value) 
...    return cls 
...  return decorator 
... 
>>> def update_x(base_values, my_value): 
... return sum(base_values + [my_value], tuple()) 
... 
>>> class Foo: x = (1,) 
... 
>>> @inherit_attribute('x', update_x) 
... class Bar(Foo): x = (2,) 
... 
>>> Bar.x 
(1, 2) 

विचार है कि आप x परिभाषित Bar में (2,) हो रहा है। सजावटी तब जायेंगे और Bar के उप-वर्गों को देखेंगे, उनके सभी x एस खोजें, और उनके साथ update_x पर कॉल करें। तो यह

update_x([(1,)], (2,)) 

यह उन्हें श्रृंखलाबद्ध से जोड़ती फोन करेगा, तो वह वापस x को बांधता है फिर से। क्या इसका कोई मतलब है?

+2

ध्यान दें कि metaclasses # 3 को हाइजैक करता है, और इसे 'टाइप' पर पास करने से पहले 'आधार' को भी संशोधित कर सकता है। तो हाँ, आप नहीं कर सकते। – delnan

+0

हां, यह समझ में आता है। मैंने खुद के बारे में सोचा (मेटाक्लास के माध्यम से), लेकिन विरासत सूची का विस्तार करना सिर्फ एक उदाहरण था। कोई इसे विस्तारित करने के बजाय सूची से कुछ आइटम हटाना चाहता है। या कोई सूची नहीं है लेकिन अन्य प्रकार ... व्यापक उत्तर के लिए धन्यवाद! – warvariuc

+0

मैंने रूबी में सुना है कि आप पूरी तरह से परिभाषित होने से पहले कक्षा तक पहुंच सकते हैं ... – warvariuc

0

कक्षा के शरीर से कोई रास्ता नहीं है; एक संदर्भ से जिसमें स्वयं उपलब्ध है (या कक्षा स्वयं), आप __bases__ की जांच कर सकते हैं।

+0

नहीं, 'स्वयं' उपलब्ध नहीं है। अन्यथा मैं 'सुपर()' – warvariuc

+0

का उपयोग कर सकता था हां, मुझे पता है कि स्वयं वर्ग के शरीर में उपलब्ध नहीं है। यही कारण है कि मैंने ऐसा कहा। यदि आप सही उत्तर पढ़ने के लिए परेशान नहीं होंगे, तो सवाल क्यों पूछें? – Marcin

1

आप मेटाक्लास या कक्षा सजावट का उपयोग कर सकते हैं।

class Klass(object): 
    my_list = [1, 2, 3] 

class KlassMeta(type): 

    def __new__(cls, name, bases, attrs): 
     # grab last base class, which in this case is Klass 
     attrs['my_list'] = bases[-1].my_list + [4, 5] 
     return super(KlassMeta, cls).__new__(cls, name, bases, attrs) 

class SubKlass(Klass): 
    __metaclass__ = KlassMeta 

अजगर 3 के साथ आप नए सिंटैक्स का उपयोग metaclass घोषित चाहते हैं:: यहाँ आप कैसे पायथन 2.x में एक metaclass का उपयोग करेंगे,

class SubKlass(Klass, metaclass=KlassMeta): 
    pass 
+0

कृपया लोगों को अनावश्यक रूप से मेटाक्लास का उपयोग करने के लिए प्रोत्साहित न करें। वे जटिल हैं और 10 बार में से 9 से बचा जाना चाहिए, उन्हें लगता है कि उन्हें एक की आवश्यकता है। ज्यादातर लोग _not_ को यह जानने की ज़रूरत नहीं है कि मेटाक्लास कैसे काम करते हैं। – gps

0

आप अन्य प्रतिक्रियाओं से देखा है के रूप में जैसे कैटरीलेक्स: नहीं, आप नहीं कर सकते। कम से कम आसानी से नहीं।

प्रश्न: आप वास्तव में क्या करने की कोशिश कर रहे हैं?

प्रश्न: आप ऐसा क्यों करना चाहते हैं?

+1

पायथन की एक अच्छी सुविधा है जो एलेक्स मार्टेलि को 'डेटा विरासत' कहते हैं। '__init__' में मैं 'self.setting1 = self.setting1 + 5' लिख सकता हूं, जहां' सेटिंग 1' एक क्लास विशेषता है। यह माता-पिता वर्ग विशेषता भी हो सकती है। बाद के उदाहरण में मैंने किसी भी विशेष कोड का उपयोग नहीं किया है, क्लास गुणों में नाम से लुकअप स्वचालित रूप से किया जाता है। मैं कक्षा शरीर के भीतर एक ही सुविधा चाहता हूँ। – warvariuc

+1

@warvariuc जो 'self.setting1' नामक एक इंस्टेंस विशेषता बनाने जा रहा है, जिसे किसी भी वर्ग विशेषता के सामने एक्सेस किया जा रहा है। तो हालांकि यह कुछ परिस्थितियों में मदद करने जा रहा है, यह लोगों को वर्ग विशेषताओं को सेट करने नहीं देगा ... – Maximilian

2

जैसा कि @ katrielalex द्वारा उत्तर दिया गया है, my_listसे कक्षा से पहले नामस्थान में नामस्थान में नहीं है। क्या होगा यदि आप metaclasses में गोता लगाने के लिए चाहते हैं आप अजगर 3 में तथापि कर सकता है,, नाम स्थान मैन्युअल रूप से करने के लिए my_list जोड़ने के लिए है:

class Meta(type): 
    def __prepare__(name, bases, **kwds): 
     print("preparing {}".format(name), kwds) 
     my_list = [] 
     for b in bases: 
      if hasattr(b, 'my_list'): 
       my_list.extend(b.my_list) 
     return {'my_list': my_list} 

class A(metaclass=Meta): 
    my_list = ["a"] 

class B(A): 
    my_list.append(2) 

print(A().my_list) 
print(B().my_list) 

ध्यान दें कि यह उदाहरण शायद अभी तक अच्छी तरह से हीरा के आकार का विरासत संरचनाओं संभाल नहीं करता है।

नया __prepare__ विशेषता PEP 3115 में परिभाषित की गई है।

+0

दिलचस्प दृष्टिकोण – warvariuc

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