2011-07-14 14 views
9

कोड के रूप में नीचे है, सिर्फ बुनियादी संरचना:निकाला जा रहा है विशिष्ट विधियों

class FooType(type): 
    def __new__(cls, name, bases, classdict): 
     instance = type.__new__(cls, name, bases, classdict) 
     # What can I do here? 
     return instance 

class FooBase(object, metaclass=FooType): 
    def __init__(self): 
     pass 

class Foo(FooBase): 
    def __init__(self, name): 
     self.name = name 

    def method1(self): 
     pass 

    def method2(self): 
     pass 

    def specialmethod(self): 
     pass 

class A(Foo): 
    pass 

class B(Foo): 
    pass 

class C(Foo): 
    _disallowed_methods = ['specialmethod'] 

मुझे क्या करना चाहते हैं, उस वर्ग C के उदाहरण specialmethod नहीं होना चाहिए है, लेकिन यह विधि A और B उदाहरणों के लिए उपलब्ध होनी चाहिए।

मैं कक्षा C में इस विधि को ओवरराइड कर सकता हूं और एक त्रुटि उठा सकता हूं, लेकिन मैं ऐसा नहीं करना चाहूंगा।

मैं मैं अगर instancedir(instance) के उत्पादन में उनमें से किसी को है FooType में _disallowed_methods के लिए और कहा कि जांच के आधार पर जांच करने के लिए कोड में जोड़ सकते हैं एहसास। लेकिन मैं अब तक की कोशिश की गई किसी भी विधि का उपयोग कर __dict__C से विधि को हटाने के लिए प्रतीत नहीं कर सकता। मैंने कोशिश की विधियों delattr(instance, 'specialmethod'), और del instance.__dict__['specialmethod'] हैं। में

delattr विधि परिणाम "AttributeError: specialmethod", और में del विधि परिणाम "लेखन त्रुटि: 'dict_proxy' ऑब्जेक्ट आइटम हटाए जाने का समर्थन नहीं करता"

मूल रूप से कई अलग अलग वर्गों Foo से इनहेरिट करेंगे, लेकिन के कुछ उनके पास C जैसे विशिष्ट विधियां उपलब्ध नहीं होनी चाहिए जिनके पास specialmethod उपलब्ध नहीं होना चाहिए।

मैं क्या गलत कर रहा हूं? या मैं इसे और कैसे पूरा कर सकता हूं?

+2

बीटीडब्ल्यू: यह [लिस्कोव प्रतिस्थापन सिद्धांत] (http://en.wikipedia.org/wiki/Liskov_substitution_principle) का उल्लंघन करेगा। – pillmuncher

उत्तर

1

Or how else can I accomplish this?

आप multiple inheritance का उपयोग करके समान परिणाम प्राप्त कर सकते हैं।

उन तरीकों को ले जाएं जिन्हें आप केवल कुछ बच्चों को Foo से ExtraFoo से ले जाना चाहते हैं। फिर class A(Foo, ExtraFoo) या class C(Foo) का उपयोग करें। इस तरह आप बच्चों के पदानुक्रम के नीचे किसी दिए गए तरीके को "पुनः" भी कर सकते हैं।

तो विधि reattaching कुछ आप रुचि रखते हैं नहीं है, तो आप बस ExtraFooFoo के एक बच्चे के रूप में हो सकता है (ताकि: विधियां जोड़ने, उन्हें अलग करने नहीं) और class A(ExtraFoo) और class C(Foo) है।

+0

मुझे एहसास हुआ कि मैं उन वर्गों के लिए 'फू' और' फूएक्स्ट्रा 'दोनों का उपयोग करके अतिरिक्त कक्षा और उप-वर्ग बनाकर कर सकता हूं, जिन्हें' विशेष विधि 'और केवल' Foo' की आवश्यकता है। मैंने सोचा कि जब मैं मेटाक्लास का उपयोग कर उदाहरण बना रहा हूं तो शायद मैं उस विधि को हटा सकता हूं। मान लीजिए कि मैं गलत था ... – skulled

+1

@skulled - पायथन बहुत लचीला है, और एक अच्छा मौका है कि आप किसी भी तरह से आंतरिक के साथ खेल सकते हैं। फिर भी, सबसे महत्वपूर्ण बात यह है कि यह खराब डिजाइन होगा। ओओपी सिद्धांतों में से एक यह है कि एक उप-वर्ग अपने माता-पिता से "उत्तराधिकारी" है, इसलिए एक उप-वर्ग "विघटित" एक विमान पर पंख बनाने की तरह होगा ** ** इसे उड़ाने के लिए नहीं! :) बीटीडब्लू: आपको उन प्रश्नों को ऊपर उठाना चाहिए जिन्हें आपने उपयोगी पाया, और - यदि कोई आपकी समस्या का समाधान करता है - तो आप इसे "स्वीकृत" के रूप में भी चिह्नित कर सकते हैं (बस उल्लेख करते हुए कि मैंने देखा है कि आप साइट पर नए हैं, अगर आप पहले से ही जानते हैं तो मुझे क्षमा करें उस)। – mac

+0

धन्यवाद! मुझे एहसास हुआ कि प्रतिक्रियाओं ने मेरे संदेह की पुष्टि के बाद शायद मैं गलत दृष्टिकोण पर विचार कर रहा था। – skulled

6

ठीक है, आप इसे इस तरह से पूरा नहीं कर सकते हैं, क्योंकि आपको C कक्षा को संशोधित नहीं करना है, लेकिन Foo कक्षा, जिसमें वास्तव में specialmethod है। लेकिन वास्तव में आप इसे नहीं कर सकते हैं क्योंकि class वैश्विक म्यूटेबल ऑब्जेक्ट है और Foo में कोई भी परिवर्तन सभी बाल वर्गों को प्रभावित करेगा।

किसी अन्य तरीके से सोचने की कोशिश करें। जैसे आप C वर्ग के पहुँचने के गुण के तर्क को संशोधित कर सकते हैं:

class C(Foo): 
    def __getattribute__(self, name): 
     if name in ['specialmethod']: 
      raise AttributeError('no such method') 
     return super(C, self).__getattribute__(name) 

कि C('a').specialmethod() बाद ट्रैसबैक पैदा करता है:

Traceback (most recent call last): 
    File "meta.py", line 37, in <module> 
    C('a').specialmethod() 
    File "meta.py", line 34, in __getattribute__ 
    raise AttributeError('no such method') 
AttributeError: no such method 
+0

मैंने इसे आजमाया (मेरी प्रारंभिक पोस्ट में उल्लेख नहीं करने के लिए माफ़ी), और अंतिम मार्ग के रूप में इस मार्ग पर जाने की योजना है। मेरी समझ से इस दृष्टिकोण का अर्थ है कि हर बार कक्षा 'सी' के उदाहरणों की विशेषता का उपयोग इस विधि के माध्यम से किया जाता है और इस प्रकार मेरी आशंका गति/प्रदर्शन पर इसका प्रभाव था। क्या वह इतना नगण्य है कि मुझे इसके बारे में चिंता करने की ज़रूरत नहीं है? – skulled

+0

@skulled हाँ, यह प्रदर्शन को प्रभावित कर सकता है। लेकिन मुझे विश्वास नहीं है कि यह आपके मामले में महत्वपूर्ण होगा। यदि आप इसके बारे में चिंता कर रहे हैं तो बस 'timeit'। –

0

आप एक माता पिता, जो आप संशोधित किया जा नहीं करना चाहती है, तो और एक एक या अधिक विरासत विधियों वाले बच्चे जिन्हें आप अप्राप्य बनाना चाहते हैं, आप वर्णनकर्ताओं के साथ ऐसा कर सकते हैं।सरल दृष्टिकोण के एक प्रयोग है property निर्मित:

class Parent: 
    def good_method(self): 
     print('Good one') 

    def bad_method(self): 
     print('Bad one') 

class Child(Parent): 
    bad_method = property(doc='(!) Disallowed inherited') 

one = Parent() 
one.good_method() # > 'Good one' 
one.bad_method() # > 'Bad one' 

two = Child() 
two.good_method() # > 'Good one' 
two.bad_method() # > AttributeError: unreadable attribute 
two.bad_method  # > AttributeError: unreadable attribute 
two.bad_method = 'Test' # > AttributeError: can't set attribute 

कैसे मदद (दो) यह प्रिंट:

class Child(Parent) 
| Method resolution order: 
|  Child 
|  Parent 
|  builtins.object 
| 
| Data descriptors defined here: 
| 
| bad_method 
|  (!) Disallowed inherited 
| 
| ---------------------------------------------------------------------- 
| Methods inherited from Parent: 
| 
| good_method(self) 
| 
| ---------------------------------------------------------------------- 
| Data descriptors inherited from Parent: 
| 
| __dict__ 
|  dictionary for instance variables (if defined) 
| 
| __weakref__ 
|  list of weak references to the object (if defined) 

सुंदर अच्छा, मेरी राय में। लेकिन आपको सावधान रहना चाहिए कि विरासत विधियों को इस तरह से भरोसा न करें (यदि प्रॉक्सी क्लास का उपयोग करके इसे बचाया जा सकता है, जो माता-पिता से विरासत में आता है और के बजाय super().bad_method() का उपयोग करने के लिए इस तरह के तरीकों को फिर से परिभाषित करता है और bad_method को स्वयं को अस्वीकार करने के लिए इंगित करता है वर्णनकर्ता)। यदि आवश्यक हो तो आप अधिक जटिल डिस्क्रिप्टर तर्क कोड कर सकते हैं

0

मैंने परीक्षण के साथ काम किया है और ठीक उसी समस्या पर ठोकर खाई है।

मुझे विरासत वर्ग से 'अनावश्यक विधियों' को हटाने का केवल एक सही तरीका मिला: इसे मूल से हटा दें। (यह बुरा विचार है, क्योंकि यह सभी मूल वर्ग के सभी उदाहरणों और सभी विरासत वर्गों के सभी उदाहरण तोड़ देगा यदि उस समारोह को कम से कम एक बार कहा जाता है)।

उदाहरण कोड:

class Base(object): 
    def excessive(self): 
     pass 

class Inher(Base): 
    def __init__(self): 
     #import pdb 
     #pdb.set_trace() 
     del Base.excessive 

b=Base() 
example = Inher() 
try: 
    example.excessive() 
except AttributeError: 
    print("Removed!") 
else: 
    raise Exception("Not removed!") 
try: 
    b.excessive() 
except AttributeError: 
    print("Unfortunately, all instances of Base no longer have .excessive() method") 

कारण यह है कि 'विरासत में मिला' तरीकों माता-पिता में संग्रहीत नहीं हैं (कोड के रूप में या लिंक के रूप में), लेकिन माता-पिता के अंदर रखा जाता है। जब कोई विधि को कॉल करता है, तो पाइथन सभी माता-पिता वर्गों के माध्यम से यात्रा करता है जब तक कि यह एक या बंद न हो जाए।

मेरे मामले में मैं इस तकनीक का उपयोग करने में सक्षम था क्योंकि मैंने अपने उद्देश्यों के लिए अन्य लोगों का परीक्षण किया था और मैंने अपना 'सेटअप/आंसूडाउन' और अक्षीय तरीकों को रखा था, लेकिन मैंने अपने सभी परीक्षण हटा दिए हैं।

कोई वास्तविक जीवन एप्लिकेशन इस तकनीक का उपयोग नहीं करना चाहिए।

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