2015-09-24 5 views
13

पायथन में, list.sort विधि और sorted अंतर्निर्मित फ़ंक्शन key नामक एक वैकल्पिक पैरामीटर स्वीकार करता है, जो एक कार्य है, जो सूची से तत्व को अपनी सॉर्टिंग कुंजी देता है।पायथन: functools cmp_to_key फ़ंक्शन कैसे काम करता है?

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

दूसरे दिन मैं तत्वों की एक सूची को सॉर्ट करना चाहता था कि cmp फ़ंक्शन key एक से लिखना अधिक आसान था। मैं एक बहिष्कृत फीचर का उपयोग नहीं करना चाहता था इसलिए मैंने प्रलेखन पढ़ा और मैंने पाया कि नामक एक मज़ेदार functools मॉड्यूल में है, जो उसके नाम के राज्यों के रूप में cmp फ़ंक्शन प्राप्त करता है और key एक देता है ... या क्या मैंने सोचा था कि जब तक मैं स्रोत कोड (या कम से कम एक बराबर संस्करण) इस उच्च स्तरीय समारोह का पढ़ा docs

def cmp_to_key(mycmp): 
    'Convert a cmp= function into a key= function' 
    class K(object): 
     def __init__(self, obj, *args): 
      self.obj = obj 
     def __lt__(self, other): 
      return mycmp(self.obj, other.obj) < 0 
     def __gt__(self, other): 
      return mycmp(self.obj, other.obj) > 0 
     def __eq__(self, other): 
      return mycmp(self.obj, other.obj) == 0 
     def __le__(self, other): 
      return mycmp(self.obj, other.obj) <= 0 
     def __ge__(self, other): 
      return mycmp(self.obj, other.obj) >= 0 
     def __ne__(self, other): 
      return mycmp(self.obj, other.obj) != 0 
    return K 

में शामिल तथ्य यह है कि cmp_to_key काम करता है के रूप में उम्मीद, मैं इस तथ्य यह है कि द्वारा हैरान पाने के बावजूद फ़ंक्शन एक फ़ंक्शन नहीं लौटाता है बल्कि इसके बजाय K क्लास देता है। क्यूं कर? यह कैसे काम करता है? मेरा अनुमान है कि sorted फ़ंक्शन आंतरिक रूप से जांचता है कि क्या सीएमपी एक फ़ंक्शन या के वर्ग या कुछ समान है, लेकिन मुझे यकीन नहीं है।

पीएस .: अपनी कठोरता के बावजूद, मैंने पाया कि के वर्ग बहुत उपयोगी है। इस कोड की जाँच करें:

from functools import cmp_to_key 

def my_cmp(a, b): 
    # some sorting comparison which is hard to express using a key function 

class MyClass(cmp_to_key(my_cmp)): 
    ... 

इस तरह, MyClass के उदाहरण के किसी भी सूची हो सकता है, डिफ़ॉल्ट रूप से, मापदंड my_cmp

उत्तर

8

नहीं, sorted फ़ंक्शन (या list.sort) आंतरिक रूप से यह जांचने की आवश्यकता नहीं है कि उसे प्राप्त ऑब्जेक्ट एक फ़ंक्शन या क्लास है या नहीं। यह सब इस बात की परवाह करता है कि key तर्क में प्राप्त ऑब्जेक्ट को कॉल करने योग्य होना चाहिए और उसे एक मान वापस करना चाहिए जिसे अन्य मूल्यों से तुलना की जा सकती है।

कक्षाएं कॉल करने योग्य भी हैं, जब आप कक्षा कहते हैं, तो आपको उस कक्षा का उदाहरण प्राप्त होता है।

आपके प्रश्न का उत्तर के लिए, पहले हम (कम से कम एक बुनियादी स्तर पर) को समझने के लिए key तर्क काम करता है की जरूरत है -

  1. key प्रतिदेय प्रत्येक तत्व के लिए कहा जाता है और यह जिसके साथ वस्तु वापस प्राप्त यह सॉर्ट करना चाहिए।

  2. नई वस्तु प्राप्त करने के बाद, यह इस तुलना अन्य वस्तुओं (फिर key othe तत्व के साथ प्रतिदेय फोन करके प्राप्त) करने के लिए।

अब यहाँ पर ध्यान देना महत्वपूर्ण बात यह है कि नई object प्राप्त अन्य ही वस्तुओं के खिलाफ तुलना में किया जाता है।

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

उदाहरण -

>>> def cmp_to_key(mycmp): 
...  'Convert a cmp= function into a key= function' 
...  class K(object): 
...   def __init__(self, obj, *args): 
...    print('obj created with ',obj) 
...    self.obj = obj 
...   def __lt__(self, other): 
...    print('comparing less than ',self.obj) 
...    return mycmp(self.obj, other.obj) < 0 
...   def __gt__(self, other): 
...    print('comparing greter than ',self.obj) 
...    return mycmp(self.obj, other.obj) > 0 
...   def __eq__(self, other): 
...    print('comparing equal to ',self.obj) 
...    return mycmp(self.obj, other.obj) == 0 
...   def __le__(self, other): 
...    print('comparing less than equal ',self.obj) 
...    return mycmp(self.obj, other.obj) <= 0 
...   def __ge__(self, other): 
...    print('comparing greater than equal',self.obj) 
...    return mycmp(self.obj, other.obj) >= 0 
...   def __ne__(self, other): 
...    print('comparing not equal ',self.obj) 
...    return mycmp(self.obj, other.obj) != 0 
...  return K 
... 
>>> def mycmp(a, b): 
...  print("In Mycmp for", a, ' ', b) 
...  if a < b: 
...   return -1 
...  elif a > b: 
...   return 1 
...  return 0 
... 
>>> print(sorted([3,4,2,5],key=cmp_to_key(mycmp))) 
obj created with 3 
obj created with 4 
obj created with 2 
obj created with 5 
comparing less than 4 
In Mycmp for 4 3 
comparing less than 2 
In Mycmp for 2 4 
comparing less than 2 
In Mycmp for 2 4 
comparing less than 2 
In Mycmp for 2 3 
comparing less than 5 
In Mycmp for 5 3 
comparing less than 5 
In Mycmp for 5 4 
[2, 3, 4, 5] 
+1

ग्रेट स्पष्टीकरण। – abc

1

में परिभाषित के अनुसार क्रमबद्ध मैं सिर्फ महसूस किया कि एक समारोह, कश्मीर नहीं होने के बावजूद कक्षा एक कॉल करने योग्य है, क्योंकि यह एक वर्ग है! और कक्षाएं कॉलबेल हैं जिन्हें कॉल किया जाता है, एक नया उदाहरण बनाता है, इसे संबंधित __init__ पर कॉल करके प्रारंभ किया जाता है और फिर उस उदाहरण को वापस कर देता है।

इस तरह यह key फ़ंक्शन के रूप में व्यवहार करता है क्योंकि के द्वारा ऑब्जेक्ट प्राप्त होने पर ऑब्जेक्ट प्राप्त होता है, और इस ऑब्जेक्ट को के उदाहरण में लपेटता है, जिसे अन्य के उदाहरणों के साथ तुलना करने में सक्षम किया जाता है।

अगर मैं गलत हूं तो मुझे सही करें। मुझे लगता है कि मैं, मेटा-क्लास क्षेत्र से अपरिचित हूं।

1

मैं स्रोत पर गौर नहीं किया, लेकिन मेरा मानना ​​है कुंजी फ़ंक्शन के परिणाम भी कुछ भी हो सकता है, और इसलिए भी एक तुलनीय वस्तु। और cmp_to_key बस उन के ऑब्जेक्ट्स का निर्माण मास्क करता है, जो कि एक दूसरे की तुलना में हैं जबकि सॉर्ट इसके काम करता है।

मैं इस तरह विभागों पर एक तरह से बना सकते हैं और कमरे के नंबर रिवर्स करने का प्रयास करें:

departments_and_rooms = [('a', 1), ('a', 3),('b', 2)] 
departments_and_rooms.sort(key=lambda vs: vs[0]) 
departments_and_rooms.sort(key=lambda vs: vs[1], reverse=True) 
departments_and_rooms # is now [('a', 3), ('b', 2), ('a', 1)] 

यही नहीं है मैं क्या चाहते हैं, और मैं तरह लगता है प्रत्येक कॉल पर ही स्थिर है, documentation imo भ्रामक है:

सॉर्ट() विधि स्थिर होने की गारंटी है। एक प्रकार स्थिर है यदि यह बराबर की तुलना करने वाले तत्वों के सापेक्ष क्रम को न बदलने की गारंटी देता है - यह एकाधिक पास में क्रमबद्ध करने के लिए सहायक है (उदाहरण के लिए, विभाग द्वारा क्रमबद्ध करें, फिर वेतन ग्रेड द्वारा)।

पुरानी शैली दृष्टिकोण से काम करता है, क्योंकि प्रत्येक परिणाम कश्मीर वर्ग बुला एक कश्मीर उदाहरण देता है और mycmp के परिणामों से उनकी तुलना:

def mycmp(a, b):        
    return cmp((a[0], -a[1]), (b[0], -b[1])) 

departments_and_rooms = [('a', 1), ('a', 3),('b', 2)] 
departments_and_rooms.sort(key=cmp_to_key(mycmp)) 
departments_and_rooms # is now [('a', 3), ('a', 1), ('b', 2)] 

यह एक महत्वपूर्ण अंतर यह है कि एक से अधिक पास सिर्फ ऐसा नहीं कर सकते है अलग सोच। कुंजी फ़ंक्शन के मानों/परिणामों को सॉर्ट करने योग्य तत्वों को सॉर्ट करने योग्य नहीं होना चाहिए। इसलिए cmp_to_key मुखौटा है: उन तुलनीय वस्तुओं को बनाने के लिए उन्हें आदेश देने की आवश्यकता है।

आशा है कि मदद करता है। और cmp_to_key कोड में अंतर्दृष्टि के लिए धन्यवाद, मुझे भी बहुत मदद मिली :)

+0

मुझे कोर का अपना पहला भाग चलाने के बाद एक ही परिणाम नहीं मिला। मुझे मिला [('ए', 3), ('बी', 2), ('ए', 1)] इसके बजाए। – matiascelasco

+1

आप सही हैं, मेरी तरफ एक कॉपी पेस्ट त्रुटि थी। मेटा-क्लास के रूप में, यह के वर्ग का उपयोग केवल सामान्य ऑब्जेक्ट इंस्टेंटेशन है। – seishin

+0

समझ में नहीं आता कि पूरी स्थिर प्रकार की चीज़ विषय से कैसे संबंधित है। क्या आप बेहतर व्याख्या कर सकते हैं? – matiascelasco

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