2008-11-26 17 views
10

मुझे पता है कि पाइथन फ़ंक्शन डिफ़ॉल्ट रूप से आभासी हैं। के मैं इस राशि मान लीजिए:फ़ंक्शन बनाना गैर ओवरराइड-सक्षम

class Foo: 
    def __init__(self, args): 
     do some stuff 
    def goo(): 
     print "You can overload me" 
    def roo(): 
     print "You cannot overload me" 

मैं उन्हें ऐसा करने के लिए सक्षम होने के लिए नहीं करना चाहती:

class Aoo(Foo): 
    def roo(): 
     print "I don't want you to be able to do this" 

वहाँ उन रू अधिक भार से रोकने के लिए एक रास्ता है()?

+2

आप ऐसी बात क्यों चाहिए? क्या आपको डर है कि कोई इसे ओवरराइड करेगा और यह उनके लिए काम नहीं करेगा? यह उनकी समस्या है। लेकिन कभी-कभी, वे जानते हैं कि वे क्या कर रहे हैं और उन्हें बस ऐसा करने की ज़रूरत है। मैंने जावा में इस तरह की सीमा के तीन दिन कामकाज बिताया है, पाइथन में यह 20 सेकंड था। – Pablo

उत्तर

32

आप एक metaclass उपयोग कर सकते हैं:

class NonOverridable(type): 
    def __new__(self, name, bases, dct): 
     if bases and "roo" in dct: 
      raise SyntaxError, "Overriding roo is not allowed" 
     return type.__new__(self, name, bases, dct) 

class foo: 
    __metaclass__=NonOverridable 
    ... 

metatype के नई जब भी एक उपवर्ग बनाई गई है कहा जाता है; यह आपके द्वारा पेश किए जाने वाले मामले में एक त्रुटि का कारण बन जाएगा। यह केवल आरयू की परिभाषा स्वीकार करेगा यदि कोई आधार वर्ग नहीं है।

एनोटेशन का उपयोग करके आप दृष्टिकोण को और अधिक फैंसी बना सकते हैं यह घोषित करने के लिए कि कौन सी विधियां अंतिम हैं; इसके बाद आपको सभी अड्डों का निरीक्षण करने और सभी अंतिम तरीकों की गणना करने की आवश्यकता है, यह देखने के लिए कि उनमें से कोई भी ओवरराइड है या नहीं।

यह अभी भी किसी भी व्यक्ति को बंदरगाह को परिभाषित करने के बाद किसी वर्ग में पैच करने से रोकता नहीं है; आप कक्षाओं के शब्दकोश के रूप में एक कस्टम शब्दकोश का उपयोग करके इन्हें पकड़ने का प्रयास कर सकते हैं (जो सभी पायथन संस्करणों में काम नहीं कर सकता है, क्योंकि कक्षाओं को क्लास डिक्शनरी को सटीक निर्देश प्रकार के होने की आवश्यकता हो सकती है)।

+0

+1 मेटाक्लास के अच्छे उदाहरण के लिए +1 __new__ –

+2

मैं आपको नफरत करता हूं, अगर मुझे आपकी कक्षा – hop

+0

का उपयोग करना पड़ा, तो क्या आप अपनी विधि को एक वर्णक के रूप में नहीं प्रदान कर सकते थे जो खुद को हटाए जाने या ओवरडिन से रोका गया था? संभावित रूप से वर्णनकर्ता केवल विशेषता लुकअप पर ट्रिगर होते हैं और नहीं, अगर वे सीधे कक्षा शब्दकोश में देखे जाते हैं। – fuzzyman

8

चूंकि पाइथन में बंदर पैचिंग है, न केवल आप कुछ भी "निजी" बना सकते हैं। भले ही आप कर सकें, फिर भी कोई भी विधि फ़ंक्शन के नए संस्करण में बंदरगाह कर सकता है।

आप इस तरह के नाम का उपयोग "निकट न जाएं" चेतावनी के रूप में कर सकते हैं।

class Foo(object): 
    def _roo(self): 
     """Change this at your own risk.""" 

यह सामान्य दृष्टिकोण है। हर कोई आपके स्रोत को पढ़ सकता है। उन्हें चेतावनी दी गई थी। अगर वे साहसपूर्वक जाते हैं जहां उन्हें जाने की चेतावनी दी जाती है, तो वे जो भी लायक होते हैं उन्हें प्राप्त करते हैं। यह काम नहीं करता है और आप उनकी मदद नहीं कर सकते हैं।

आप इसे "निजी" विधियों द्वारा बुलाए जाने वाले आंतरिक वर्गों और "छिपा" कार्यान्वयन मॉड्यूल के साथ जानबूझकर अस्पष्ट करने की कोशिश कर सकते हैं। लेकिन ... हर किसी का आपका स्रोत है। आप को कुछ भी नहीं रोक सकते हैं। आप केवल लोगों को उनके कार्यों के परिणामों की सलाह दे सकते हैं।

6
def non_overridable(f): 
    f.non_overridable = True 
    return f 

class ToughMeta(type): 
    def __new__(cls, name, bases, dct): 
     non_overridables = get_non_overridables(bases) 
     for name in dct: 
      if name in non_overridables: 
       raise Exception ("You can not override %s, it is non-overridable" % name) 
     return type.__new__(cls, name, bases, dct) 

def get_non_overridables(bases): 
    ret = [] 
    for source in bases: 
     for name, attr in source.__dict__.items(): 
      if getattr(attr, "non_overridable", False): 
       ret.append(name) 
     ret.extend(get_non_overridables(source.__bases__)) 
    return ret 

class ToughObject(object): 
    __metaclass__ = ToughMeta 
    @non_overridable 
    def test1(): 
     pass 

# Tests --------------- 
class Derived(ToughObject): 
    @non_overridable 
    def test2(self): 
     print "hello" 

class Derived2(Derived): 
    def test1(self): 
     print "derived2" 

# -------------------- 
0

पार्टी के लिए देर से लेकिन सभी अजगर तरीकों "आभासी" डिफ़ॉल्ट रूप से कर रहे हैं - पर विचार करें:

class B(object): 
    def __priv(self): print '__priv:', repr(self) 

    def call_private(self): 
     print self.__class__.__name__ 
     self.__priv() 

class E(B): 
    def __priv(self): super(E, self).__priv() 

    def call_my_private(self): 
     print self.__class__.__name__ 
     self.__priv() 

B().call_private() 
E().call_private() 
E().call_my_private() 

चल रही है कारण नाम mangling रहे हैं:

B 
__priv: <__main__.B object at 0x02050670> 
E 
__priv: <__main__.E object at 0x02050670> 
E 
Traceback (most recent call last): 
    File "C:/Users/MrD/.PyCharm2016.3/config/scratches/test_double__underscore", line 35, in <module> 
    E().call_my_private() 
    File "C:/Users/MrD/.PyCharm2016.3/config/scratches/test_double__underscore", line 31, in call_my_private 
    self.__priv() 
    File "C:/Users/MrD/.PyCharm2016.3/config/scratches/test_double__underscore", line 27, in __priv 
    def __priv(self): super(E, self).__priv() 
AttributeError: 'super' object has no attribute '_E__priv' 

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

"""DON'T OVERRIDE THIS METHOD""" 
संबंधित मुद्दे