2012-12-10 13 views
6

क्या यह मुझे या पायथन है जो निम्नलिखित कोड से उलझन में है? मैं उम्मीद करेंगे __le__a <= ab द्वारा कहा जाता था, __ge__ नहीं:पायथन बग __le__, __ge__ के साथ?

#!/usr/bin/env python2 

class B(object): 
    def __ge__(self, other): 
     print("__ge__ unexpectedly called") 

class A(object): 
    def __le__(self, other): 
     print("__le__ called") 

class AB(A, B): 
    pass 

a = A() 
ab = AB() 

a <= ab # --> __ge__ unexpectedly called 
ab <= a # --> __le__ called 

मैं अजगर 2.7, 3.2 के साथ समान व्यवहार हो और PyPy 1.9।

__ge__ के बजाय बुलाया जाने के लिए मैं क्या कर सकता हूं ??

+2

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

+0

वास्तव में, आपके द्वारा प्रस्तावित सरलीकृत संस्करण एक ही व्यवहार भी है। अब सही किया गया। – user474491

उत्तर

8

संक्षिप्त उत्तर यह है कि वे से व्यवहार को ओवरराइड करने के लिए AB को अनुमति देना चाहते थे। पाइथन AB.__lt__(a, ab) पर कॉल नहीं कर सकता है, क्योंकि a विधि के लिए वैध self मान्य नहीं हो सकता है, इसलिए इसके बजाय, यह AB.__gt__(ab, a) पर मान्य है, जो मान्य है।

लंबा उत्तर थोड़ा और जटिल है।

rich comparison operators के लिये दस्तावेज के अनुसार:

इन तरीकों में से कोई बदली-तर्क संस्करणों (जब बाईं तर्क आपरेशन का समर्थन नहीं करता है, लेकिन सही तर्क करता है प्रयोग की जाने वाली) हैं; बल्कि, __lt__() और __gt__() एक दूसरे के प्रतिबिंब हैं, __le__() और __ge__() एक-दूसरे के प्रतिबिंब हैं, और __eq__() और __ne__() उनके स्वयं के प्रतिबिंब हैं।

दूसरे शब्दों में, x <= y बिल्कुल वैसा ही मामलों में y.__ge__(x) फोन जहां x+yy.__radd__(x) कहेंगे होगा। की तुलना करना:

>>> class X(object): 
...  def __add__(self, other): 
...   print('X.add') 
>>> class Y(object): 
...  def __radd__(self, other): 
...   print('Y.radd') 
>>> class XY(X, Y): 
...  pass 
>>> x, xy = X(), XY() 
>>> x + xy 
Y.radd 

reflected operators के लिये दस्तावेज के अनुसार:

इन विधियों द्विआधारी अंकगणितीय आपरेशनों लागू करने के लिए कहा जाता है ... परिलक्षित के साथ (बदली) ऑपरेंड। इन कार्यों केवल कहा जाता है, तो बाईं संकार्य इसी आपरेशन का समर्थन नहीं करता और ऑपरेंड विभिन्न प्रकार के होते हैं ...

नोट: सही संकार्य के प्रकार बाईं संकार्य के प्रकार का एक उपवर्ग है और कहा कि उपवर्ग परिलक्षित प्रदान करता है ऑपरेशन के लिए विधि, इस विधि को बाएं ऑपरेंड की गैर-परावर्तित विधि से पहले बुलाया जाएगा। यह व्यवहार उप-वर्गों को अपने पूर्वजों के संचालन को ओवरराइड करने की अनुमति देता है।

तो, क्योंकि XYX का एक उपवर्ग है, XY.__radd__X.__add__ की तुलना में प्राथमिकता हो जाता है। और, इसी प्रकार, क्योंकि ABA का उप-वर्ग है, AB.__ge__A.__le__ से अधिक प्राथमिकता प्राप्त करता है।

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

अंत में, इस मामले अजीब लगता है, क्योंकि AB, बल्कि __ge__ अधिभावी से भी, बस इसे से विरासत में मिली B, जोके बारे में कुछ भी नहीं जानताऔर इससे संबंधित नहीं है। संभवतः B का इरादा नहीं था कि इसके सबक्लास A के व्यवहार को ओवरराइड करें। लेकिन B को A -युक्त कक्षाओं के लिए मिश्रित के रूप में उपयोग करने के लिए उपयोग किया गया था, शायद यह बिल्कुल इस तरह के ओवरराइड का इरादा रखेगा। और किसी भी दर पर, नियम शायद एमआरओ में से प्रत्येक विधि कहां से प्राप्त किए बिना पर्याप्त जटिल है। तर्क जो भी हो, जहां __ge__ अप्रासंगिक है; अगर यह सबक्लास पर है, तो इसे बुलाया जाता है।

अपने जोड़ा अंतिम, प्रश्न के लिए, अच्छी तरह से, तुम सच में नहीं, किसी भी अधिक की तुलना में आप X.__add__XY.__radd__ के बजाय कहा जाता है प्राप्त कर सकते हैं कर सकते हैं "क्या मैं __le____ge__ के बजाय कहा जाता प्राप्त करने के लिए क्या कर सकते हैं ??" ...। बेशक आप AB.__ge__ (या XY.__radd__) को हमेशा A.__le__ (या X.__add__) पर कॉल कर सकते हैं, लेकिन AB.__ge__ को इस तरह से लागू करने के लिए संभवतः यह आसान है कि यह A के साथ पहले स्थान पर अन्य तर्क के रूप में कार्य करता है। वैकल्पिक रूप से, आप विरासत को हटा सकते हैं और जिस तरह से आप मॉडलिंग कर रहे थे उसे मॉडल करने के लिए कुछ और तरीका ढूंढ सकते हैं। या आप a<=ab के बजाय a.__le__(ab) को स्पष्ट रूप से कॉल कर सकते हैं। लेकिन अन्यथा, यदि आपने अपनी कक्षाओं को ऐसे तरीके से डिज़ाइन किया है जो अजीब कुछ करने के लिए "कोई अंतर्निहित रिश्ते" का लाभ उठाता है, तो आपको दस्तावेज़ों द्वारा गुमराह किया गया था, और उन्हें किसी भी तरह से फिर से डिजाइन करना होगा।

+0

मुझे पता है, लेकिन '__le__' कब उपलब्ध है, तो यह' __ge__' क्यों कॉल करेगा ?? – user474491

+1

क्योंकि "दाएं ऑपरेंड का प्रकार बाएं ऑपरेंड के प्रकार का उप-वर्ग है और वह सबक्लास प्रतिबिंबित विधि प्रदान करता है", जो "उप-वर्गों को अपने पूर्वजों के संचालन को ओवरराइड करने की अनुमति देता है"। (यदि आप पूछ रहे हैं कि क्यों यह ध्यान दिया जाना चाहिए कि 'एबी' को 'बी' से '__ge__' विरासत में डालने के बजाय विरासत में मिला है, जिसे नियम द्वारा ध्यान में नहीं रखा जाता है। शायद क्योंकि चीजें इसे जोड़कर पर्याप्त जटिल हैं मिश्रण के लिए।) – abarnert

+2

@ बार्नर्ट ने अपने उत्तर (+1, बीटीडब्ल्यू) में उल्लेख किया है कि यह अधिक व्युत्पन्न वर्ग प्राथमिकता देना है, ताकि इसे व्यवहार को ओवरराइड करने की अनुमति दी जा सके। – jimhark

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