धोने योग्य, अपरिवर्तनीय


81

हाल ही में एक एसओ प्रश्न से ( अजगर में एक शब्दकोश बनाएं जो सूचियों द्वारा अनुक्रमित है ) मुझे एहसास हुआ कि मुझे शायद अजगर में धोए और अपरिवर्तनीय वस्तुओं के अर्थ का गलत अनुमान था।

  • व्यावहारिक रूप से धोने का क्या मतलब है?
  • हैज़ेबल और इमम्युटेबल के बीच क्या संबंध है?
  • क्या ऐसी उत्परिवर्तनीय वस्तुएं हैं, जो धोए जाने योग्य या अपरिवर्तनीय वस्तुएं हैं, जो कि धोने योग्य नहीं हैं?

जवाबों:


85

हैशिंग एक बड़ी मात्रा में डेटा की एक बड़ी मात्रा (आमतौर पर एक पूर्णांक) को दोहराने योग्य तरीके से परिवर्तित करने की प्रक्रिया है, ताकि इसे निरंतर-तालिका में तालिका में देखा जा सके O(1), जो उच्च-प्रदर्शन के लिए महत्वपूर्ण है एल्गोरिदम और डेटा संरचनाएं।

अपरिवर्तनीयता यह विचार है कि किसी वस्तु को बनाने के बाद कुछ महत्वपूर्ण तरीके से नहीं बदलेगा, विशेष रूप से किसी भी तरह से उस वस्तु के हैश मान को बदल सकता है।

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

वास्तव में उस विचार को समझने के लिए जिसे आपको C / C ++ जैसी भाषा में अपने स्वयं के हैशटेबल को लागू करने का प्रयास करना चाहिए, या HashMapकक्षा के जावा कार्यान्वयन को पढ़ना चाहिए ।


1
इसके अलावा, हैश टेबल्स के लिए यह पता लगाना संभव नहीं है कि कब किसकी हैश बदल जाए (किसी भी कुशल तरीके से कम से कम)। यह एक सामान्य नुकसान है जैसे कि जावा में जहाँ HashMapआप एक कुंजी के रूप में उपयोग की जाने वाली वस्तु को संशोधित करते हैं तो टूट जाता है: न तो पुरानी और न ही नई कुंजी मिल सकती है, भले ही आप नक्शे को प्रिंट करते हों, यह वहां देखा जा सकता है।
डबलू

1
धोने योग्य और अपरिवर्तनीय कुछ हद तक संबंधित हैं लेकिन समान नहीं हैं। उदाहरण के लिए विरासत objectमें मिली कस्टम क्लासेस से बनाए गए उदाहरण हैं, लेकिन वे अपरिवर्तनीय नहीं हैं। इन उदाहरणों का उपयोग एक तानाशाह की चाबी हो सकता है, लेकिन अगर वे चारों ओर से गुजरते हैं, तो भी उन्हें संशोधित किया जा सकता है।
प्रांजल मित्तल

13
  • क्या ऐसी उत्परिवर्तनीय वस्तुएं हैं, जो धोए जाने योग्य या अपरिवर्तनीय वस्तुएं हैं, जो कि धोने योग्य नहीं हैं?

पाइथन में, टूपल अपरिवर्तनीय है, लेकिन यह केवल तभी धो सकता है जब इसके सभी तत्व धुले हों।

>>> tt = (1, 2, (30, 40))
>>> hash(tt)
8027212646858338501
>>> tl = (1, 2, [30, 40])
>>> hash(tl)
TypeError: unhashable type: 'list'

धोने योग्य प्रकार

  • परमाणु अपरिवर्तनीय प्रकार सभी हशेबल हैं, जैसे कि str, बाइट्स, न्यूमेरिक प्रकार
  • एक जमे हुए सेट हमेशा धोने योग्य होता है (इसके तत्वों को परिभाषा द्वारा धोया जाना चाहिए)
  • एक टपल केवल तभी धो सकता है, जब उसके सभी तत्व उपलब्ध हों
  • उपयोगकर्ता-परिभाषित प्रकार डिफ़ॉल्ट रूप से धो सकते हैं क्योंकि उनका हैश मान उनकी आईडी () है

8

से अजगर शब्दावली :

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

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

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

हैट्स और सेट को हैश तालिका में कुशल देखने के लिए हैश का उपयोग करना चाहिए; हैश मान अपरिवर्तनीय होना चाहिए, क्योंकि हैश बदलने से डेटा संरचनाएं गड़बड़ हो जाएंगी और तानाशाह या असफल होने का कारण बन जाएगा। हैश मान को अपरिवर्तनीय बनाने का सबसे आसान तरीका यह है कि संपूर्ण वस्तु को अपरिवर्तनीय बनाया जाए, यही वजह है कि दोनों को अक्सर एक साथ उल्लेखित किया जाता है।

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


@Andrey: फ्रोज़ेनसेट्स धोने योग्य हैं, सेट नहीं हैं; दोनों में केवल धोने योग्य आइटम हो सकते हैं। जिन स्थानों पर मार्क ने उल्लेख किया है, वह सही था, इसलिए मुझे नहीं लगता कि उनका मतलब फ्रेंजेंस था।
tzot

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

1
@ScottGriffiths मुझे नहीं पता कि आपकी टिप्पणी को देखने के लिए मुझे 6 साल क्यों लगे, लेकिन पहले से कहीं ज्यादा देर हो गई। मुझे नहीं पता कि मैं इतना दूर कैसे जा सकता था, यह देखते हुए कि मैंने एक सी ++ सेट में उत्परिवर्तनीय वस्तुओं को डालने में असमर्थता व्यक्त की है। मुझे उम्मीद है कि मेरे संपादन चीजों को ठीक करता है।
मार्क रैनसम

7

तकनीकी रूप से, धोने योग्य का मतलब है कि वर्ग परिभाषित करता है __hash__()। डॉक्स के अनुसार:

__hash__()एक पूर्णांक वापस करना चाहिए। केवल आवश्यक संपत्ति यह है कि जो वस्तुएं समान की तुलना करती हैं उनका समान हैश मूल्य होता है; यह किसी भी तरह एक साथ मिलाने की सलाह दी जाती है (उदाहरण के लिए अनन्य या) वस्तु के घटकों के लिए हैश मान जो वस्तुओं की तुलना में एक भूमिका निभाते हैं।

मुझे लगता है कि पायथन बिल्डिन प्रकारों के लिए, सभी धोने योग्य प्रकार भी अपरिवर्तनीय हैं।

यह मुश्किल होगा, लेकिन शायद यह संभव नहीं है कि एक परस्पर परिवर्तन योग्य वस्तु जो फिर भी परिभाषित हो __hash__()


1
यह ध्यान देने योग्य है कि __hash__ऑब्जेक्ट को वापस करने के लिए डिफ़ॉल्ट रूप से परिभाषित किया गया है id; आपको __hash__ = Noneइसे बिना सोचे-समझे सेट करने के लिए अपने रास्ते से बाहर जाना होगा । मार्क रैनसम के रूप में भी उल्लेख है कि अगर हैश मूल्य कभी नहीं बदल सकता है तो यह एक अतिरिक्त शर्त है!
स्कॉट ग्रिफ़िथ

5
मुझे लगता है कि उत्तर थोड़ा भ्रामक है, इस अर्थ में listपरिभाषित करता __hash__है कि hasattr([1,2,3], "__hash__")रिटर्न True, हालांकि कॉलिंग hash([1,2,3])एक TypeError(पायथन 3) को उठाता है , इसलिए यह वास्तव में धोने योग्य नहीं है। के अस्तित्व पर भरोसा करने के लिए __hash__पर्याप्त नहीं है अगर कुछ है) निर्धारित करने के लिए पर्याप्त है) बी) अपरिवर्तनीय
मैटी

4

अंतर के कारण अपरिवर्तनीय और धोने योग्य के बीच कोई स्पष्ट संबंध नहीं होने पर भी निहितार्थ है

  1. हेशिबल ऑब्जेक्ट जो समान की तुलना करते हैं, उनका समान हैश मान होना चाहिए
  2. यदि कोई हैश वैल्यू है, तो कोई वस्तु नहीं है, जो उसके जीवनकाल में कभी नहीं बदलती है।

यहां कोई समस्या नहीं है जब तक आप पुनर्परिभाषित __eq__नहीं करते हैं, इसलिए ऑब्जेक्ट क्लास मूल्य पर तुल्यता को परिभाषित करता है।

एक बार जब आप ऐसा कर लेते हैं, तो आपको एक स्थिर हैश फ़ंक्शन खोजने की आवश्यकता होती है, जो हमेशा उन वस्तुओं के लिए समान मूल्य देता है जो समान मूल्य का प्रतिनिधित्व करते हैं (उदाहरण के लिए, जहां __eq__) सही लौटाता है, और किसी वस्तु के जीवनकाल के दौरान कभी नहीं बदलता है।

एक आवेदन को देखना मुश्किल है जहां यह संभव है, एक संभावित वर्ग पर विचार करें जो इन आवश्यकताओं को पूरा करता है। हालांकि स्पष्ट पतित मामला है जहां __hash__एक निरंतरता लौटती है।

अभी:-

>>> a = A(1)
>>> b = A(1)
>>> c = A(2)
>>> a == b
True
>>> a == c
False
>>> hash(a) == hash(b)
True
>>> a.set_value(c)
>>> a == c
True
>>> assert(hash(a) == hash(c)) # Because a == c => hash(a) == hash(c)
>>> assert(hash(a) == hash(b)) # Because hash(a) and hash(b) have compared equal 
                                 before and the result must stay static over the objects lifetime.

वास्तव में इसका मतलब है कि सृजन हैश (बी) == हैश (सी) के बावजूद, इस तथ्य की कभी भी तुलना नहीं की जाती है। मैं वैसे भी __hash__एक परिभाषित करने योग्य वस्तु के लिए उपयोगी परिभाषित () को परिभाषित करने के लिए संघर्ष करता हूं जो मूल्य की तुलना को परिभाषित करता है।

नोट : __lt__, __le__, __gt__और __ge__comparsions प्रभावित नहीं होते हैं तो आप अभी भी hashable वस्तुओं, परिवर्तनशील या अन्यथा उनके मूल्य के आधार पर की एक आदेश परिभाषित कर सकते हैं।


3

सिर्फ इसलिए कि यह शीर्ष Google हिट है, यहां एक परिवर्तनशील वस्तु को धोने योग्य बनाने का एक सरल तरीका है:

>>> class HashableList(list):
...  instancenumber = 0  # class variable
...  def __init__(self, initial = []):
...   super(HashableList, self).__init__(initial)
...   self.hashvalue = HashableList.instancenumber
...   HashableList.instancenumber += 1
...  def __hash__(self):
...   return self.hashvalue
... 
>>> l = [1,2,3]
>>> m = HashableList(l)
>>> n = HashableList([1,2,3])
>>> m == n
True
>>> a={m:1, n:2}
>>> a[l] = 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> m.hashvalue, n.hashvalue
(0, 1)

मैं वास्तव में कुछ इस तरह के लिए एक उपयोग पाया जब एक वर्ग बनाने के लिए SQLAlchemy रिकॉर्ड करने के लिए कुछ म्यूट और मेरे लिए अधिक उपयोगी है, जबकि तानाशाही कुंजी के रूप में उपयोग के लिए उनकी हैशबैलिटी बनाए रखते हुए।


3

अपरिवर्तनीय का अर्थ है कि वस्तु अपने जीवनकाल के दौरान किसी भी महत्वपूर्ण तरीके से नहीं बदलेगी। यह प्रोग्रामिंग भाषाओं में एक अस्पष्ट लेकिन सामान्य विचार है।

Hashability थोड़ा अलग है, और तुलना करने के लिए संदर्भित करता है।

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

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

आपके द्वारा घोषित किसी भी नए वर्ग की वस्तुओं को शब्दकोश कुंजी के रूप में उपयोग किया जा सकता है, जब तक कि आप इसे रोकते नहीं हैं, उदाहरण के लिए, इससे फेंकना __hash__

हम कह सकते हैं कि सभी अपरिवर्तनीय वस्तुएं हैंज़ेबल हैं, क्योंकि यदि ऑब्जेक्ट के जीवनकाल के दौरान हैश बदल जाता है, तो इसका मतलब है कि ऑब्जेक्ट उत्परिवर्तित हो गया है।

लेकिन काफी नहीं। एक टपल पर विचार करें जिसमें एक सूची (परस्पर) है। कुछ लोग कहते हैं कि टप्पर अपरिवर्तनीय है, लेकिन एक ही समय में यह कुछ हद तक नहीं है।

d = dict()
d[ (0,0) ] = 1    #perfectly fine
d[ (0,[0]) ] = 1  #throws

Hashability और अपरिवर्तनीयता ऑब्जेक्ट इंस्टेंसेस को संदर्भित करते हैं, टाइप नहीं। उदाहरण के लिए, टाइप टपल का एक ऑब्जेक्ट हैज़ेबल हो सकता है या नहीं।


1
"समान वस्तुओं की तुलना करने वाली हैश वाली वस्तुओं का मूल्य समान हैश होना चाहिए।" क्यों? मैं उन वस्तुओं का निर्माण कर सकता हूं जो समान की तुलना करते हैं लेकिन उनके पास समान हैश मूल्य नहीं है।
एंडोलिथ

1
ऐसी वस्तुओं को बनाना संभव है, लेकिन यह पायथन प्रलेखन में परिभाषित अवधारणा का उल्लंघन होगा। विचार यह है कि, वास्तव में, हम इस आवश्यकता का उपयोग ऐसे (तार्किक रूप से समतुल्य) निहितार्थ प्राप्त करने के लिए कर सकते हैं: यदि हैश बराबर नहीं हैं, तो ऑब्जेक्ट समान नहीं हैं। बहुत उपयोगी। कई कार्यान्वयन, कंटेनर और एल्गोरिदम चीजों को गति देने के लिए इस निहितार्थ पर भरोसा करते हैं।
14:26 पर user2622016

सामान्य मामले जहां comparison != identity"अवैध" मूल्यों की तुलना एक साथ की जाती है float("nan") == float("nan"), जैसे कि या स्लाइस से जुड़े तार: "apple" is "apple"बनाम"apple" is "crabapple"[4:]
स्लीपब्लैंक

1

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

अन्य भाषाओं में, हैश मूल्य वस्तुओं की पहचान से अधिक संबंधित है, और मूल्य के लिए नहीं (आवश्यक रूप से)। इस प्रकार, एक उत्परिवर्तनीय वस्तु के लिए, हैशिंग को शुरू करने के लिए सूचक का उपयोग किया जा सकता है। यह मानते हुए कि स्मृति में कोई वस्तु नहीं चलती (जैसा कि कुछ GC करते हैं)। उदाहरण के लिए, लुआ में इसका उपयोग किया जाता है। यह एक टेबल टेबल के रूप में प्रयोग करने योग्य वस्तु को बनाता है; लेकिन newbies के लिए कई (अप्रिय) आश्चर्य पैदा करता है।

अंत में, एक अपरिवर्तनीय अनुक्रम प्रकार (ट्यूपल्स) होने से यह 'बहु-मूल्य कुंजियों' के लिए अच्छा है।


3
@ जेवियर: 'पाइथन में वे ज्यादातर विनिमेय हैं' मेरा संदेह छोटे हिस्से को 'ज्यादातर' में शामिल नहीं करता है
joaquin

0

हैशबल का मतलब है कि एक चर का मान एक स्थिर - स्ट्रिंग, संख्या, आदि द्वारा प्रतिनिधित्व किया जा सकता है (या, बल्कि, एन्कोडेड), अब कुछ ऐसा है जो परिवर्तन के अधीन है (परिवर्तनशील) उस चीज द्वारा प्रतिनिधित्व नहीं किया जा सकता है जो नहीं है। इसलिए, कोई भी परिवर्तनशील जो परिवर्तनशील है, वह धोने योग्य नहीं हो सकता है और उसी टोकन से, केवल अपरिवर्तनीय चर ही धोने योग्य हो सकते हैं।

उम्मीद है की यह मदद करेगा ...

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.