python पायथन कार्य क्यों और कैसे हैं?




hash (3)

यह कुछ खास नहीं है। जैसा कि आप देख सकते हैं कि क्या आप फ़ंक्शन प्रकार की अनबाउंड __hash__ विधि की जांच करते हैं:

>>> def f(): pass
...
>>> type(f).__hash__
<slot wrapper '__hash__' of 'object' objects>

of 'object' objects भाग का अर्थ है कि यह of 'object' objects से डिफ़ॉल्ट पहचान-आधारित __hash__ प्राप्त करता object । फंक्शन == और hash पहचान द्वारा काम करते हैं। id और hash बीच का अंतर सामान्य प्रकार के किसी भी प्रकार के लिए सामान्य है object.__hash__ :

>>> x = object()
>>> id(x)
40145072L
>>> hash(x)
2509067

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

मैंने हाल ही में पायथन में निम्नलिखित आदेशों का प्रयास किया:

>>> {lambda x: 1: 'a'}
{<function __main__.<lambda>>: 'a'}

>>> def p(x): return 1
>>> {p: 'a'}
{<function __main__.p>: 'a'}

दोनों dict creations की सफलता से संकेत मिलता है कि लैम्ब्डा और नियमित कार्य दोनों ही हैंशबल हैं। (कुछ ऐसा है {[]: 'a'} TypeError: unhashable type: 'list' साथ विफल रहता है TypeError: unhashable type: 'list' )।

हैश स्पष्ट रूप से समारोह की आईडी नहीं है:

>>> m = lambda x: 1
>>> id(m)
140643045241584
>>> hash(m)
8790190327599
>>> m.__hash__()
8790190327599

आखिरी कमांड से पता चलता है कि __hash__ विधि को lambda लिए स्पष्ट रूप से परिभाषित किया गया है, यानी, यह कुछ स्वैच्छिक चीज नहीं है जो कि पाइथन गणना के आधार पर गणना करता है।

कार्यों को बनाने योग्य बनाने के पीछे प्रेरणा क्या है? बोनस के लिए, फ़ंक्शन का हैश क्या है?


एक समारोह हैशबल है क्योंकि यह एक सामान्य, निर्मित, गैर परिवर्तनीय वस्तु है।

पायथन मैनुअल से :

एक ऑब्जेक्ट हैशबल है यदि उसके पास हैश वैल्यू है जो अपने जीवनकाल के दौरान कभी नहीं बदलता है (इसे __hash__() विधि की आवश्यकता होती है), और इसकी तुलना अन्य वस्तुओं से की जा सकती है (इसे __eq__() या __cmp__() विधि की आवश्यकता है)। हैशबल ऑब्जेक्ट्स जो बराबर की तुलना में समान हैश मान होना चाहिए।

हैशबिलिटी एक ऑब्जेक्ट को एक कुंजीपटल कुंजी और सेट सदस्य के रूप में उपयोग करने योग्य बनाता है, क्योंकि ये डेटा संरचनाएं आंतरिक रूप से हैश मान का उपयोग करती हैं।

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


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

इस्तेमाल किया गया एल्गोरिदम पायथन के संस्करण पर निर्भर करता है। ऐसा लगता है कि आप 64-बिट बॉक्स पर पायथन के हाल के संस्करण का उपयोग कर रहे हैं। उस स्थिति में, फ़ंक्शन ऑब्जेक्ट का हैश अपने id() द्वारा 4 बिट्स का दायां रोटेशन है, जिसके परिणामस्वरूप हस्ताक्षरित 64-बिट पूर्णांक के रूप में देखा जाता है। सही शिफ्ट किया जाता है क्योंकि ऑब्जेक्ट पतों ( id() परिणाम) आमतौर पर गठबंधन होते हैं ताकि उनकी अंतिम 3 या 4 बिट हमेशा 0 हों, और यह हैश फ़ंक्शन के लिए एक हल्की कष्टप्रद संपत्ति है।

आपके विशिष्ट उदाहरण में,

>>> i = 140643045241584 # your id() result
>>> (i >> 4) | ((i << 60) & 0xffffffffffffffff) # rotate right 4 bits
8790190327599  # == your hash() result




hash