पायथन हैश () फ़ंक्शन में निर्मित


82

विंडोज एक्सपी, पायथन 2.5:

hash('http://stackoverflow.com') Result: 1934711907

Google App Engine ( http://shell.appspot.com/ ):

hash('http://stackoverflow.com') Result: -5768830964305142685

ऐसा क्यों है? मेरे पास एक हैश फ़ंक्शन कैसे हो सकता है जो मुझे विभिन्न प्लेटफार्मों (विंडोज, लिनक्स, मैक) पर समान परिणाम देगा?


14
यह इस तथ्य के कारण है कि आपका winxp एक 32 बिट प्लेटफॉर्म है, जबकि Google का 64 बिट है
Tzury Bar Yochay

जवाबों:


56

हैशलीब का उपयोग करें जैसा hash() कि डिजाइन किया गया था :

एक शब्दकोश देखने के दौरान शब्दकोश कुंजी की तुलना जल्दी करें

और इसलिए यह गारंटी नहीं देता है कि यह पायथन कार्यान्वयन के समान होगा।


5
hashlibगैर-क्रिप्टोग्राफ़िक उपयोग के लिए हैश फ़ंक्शन थोड़ा धीमा नहीं है?
ब्रैंडन रोड्स

8
जेनकिन्स, बर्नस्टीन, एफएनवी, मुरमुरैश, और कई अन्य जैसे सामान्य प्रयोजन हैश कार्यों की तुलना में वे वास्तव में बहुत धीमी हैं। यदि आप अपनी खुद की हैश टेबल जैसी संरचना बनाना चाहते हैं, तो मैं सुझाव देता हूं कि uthash.h uthash.sourceforge.net
lericson

45
बेंचमार्क: hash95 एनएस, binascii.crc32570 एनएस, hashlib.md5.digest()1.42 हमसे, murmur.string_hash234 एनएस
टेम्पो

hashप्रत्येक अजगर सत्र के साथ एक नया बेतरतीब ढंग से उत्पन्न नमक मूल्य का उपयोग करता है। तो यह अजगर सत्रों के बीच बदल जाएगा।
hobs

89

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

>>> class Foo:
...     pass
... 
>>> a = Foo()
>>> b = Foo()
>>> hash(a), hash(b)
(-1210747828, -1210747892)

जैसा कि आप देख सकते हैं, वे अलग-अलग हैं, क्योंकि हैश () __hash__SHA जैसे 'सामान्य' हैशिंग एल्गोरिदम के बजाय ऑब्जेक्ट की विधि का उपयोग करता है ।

उपरोक्त को देखते हुए, तर्कसंगत विकल्प हैशलीब मॉड्यूल का उपयोग करना ।


धन्यवाद! मैं यह सोचकर यहाँ आया था कि क्यों मुझे हमेशा समान वस्तुओं के लिए अलग-अलग हैश मूल्य मिलेंगे, जिसके परिणामस्वरूप डायक्ट्स के साथ अप्रत्याशित व्यवहार (जो समानता के लिए जाँच करने के बजाय हैश + प्रकार के सूचकांक)। Hashlib.md5 से अपना स्वयं का इंट हैश उत्पन्न करने का एक त्वरित तरीका है int(hashlib.md5(repr(self)).hexdigest(), 16)(यह मानकर कि self.__repr__इसे समान iff ऑब्जेक्ट समान माना गया है)। यदि 32 बाइट्स बहुत लंबी हैं, तो आप रूपांतरण से पहले हेक्स स्ट्रिंग को स्लाइस करके निश्चित रूप से आकार में कटौती कर सकते हैं।
एलन प्लम

1
दूसरे विचार पर, यदि __repr__आप पर्याप्त अद्वितीय हैं, तो आप बस str.__hash__(यानी hash(repr(self))) का उपयोग कर सकते हैं क्योंकि डाइट्स गैर-बराबर वस्तुओं को एक ही हैश के साथ नहीं मिलाते हैं। यह केवल तभी काम करता है जब वस्तु पर्याप्त रूप से तुच्छ हो, जो कि प्रतिनिधि पहचान का प्रतिनिधित्व कर सके।
एलन प्लम

तो, दो वस्तुओं के साथ आपके उदाहरण में aऔर b, मैं यह देखने के लिए कि कैसे समान हैं, हैशलीब मॉड्यूल का उपयोग कैसे कर सकता हूं?
गैरेट


32

प्रतिक्रिया बिल्कुल आश्चर्य की बात नहीं है: वास्तव में

In [1]: -5768830964305142685L & 0xffffffff
Out[1]: 1934711907L

इसलिए यदि आप ASCII स्ट्रिंग्स पर विश्वसनीय प्रतिक्रियाएं प्राप्त करना चाहते हैं , तो बस निम्न 32 बिट्स प्राप्त करें uint। स्ट्रिंग्स के लिए हैश फ़ंक्शन 32-बिट-सुरक्षित और लगभग पोर्टेबल है।

दूसरी तरफ, आप hash()किसी भी ऐसी वस्तु को प्राप्त करने पर भरोसा नहीं कर सकते हैं जिस पर आपने स्पष्ट रूप से __hash__अयोग्य होने की विधि को परिभाषित नहीं किया है।

ASCII स्ट्रिंग्स पर यह सिर्फ इसलिए काम करता है क्योंकि हैश की गणना स्ट्रिंग बनाने वाले एकल वर्णों पर की जाती है, जैसे कि निम्नलिखित:

class string:
    def __hash__(self):
        if not self:
            return 0 # empty
        value = ord(self[0]) << 7
        for char in self:
            value = c_mul(1000003, value) ^ ord(char)
        value = value ^ len(self)
        if value == -1:
            value = -2
        return value

जहां c_mulफ़ंक्शन सी के रूप में "चक्रीय" गुणन (अतिप्रवाह के बिना) है।


18

अधिकांश उत्तर बताते हैं कि यह विभिन्न प्लेटफार्मों के कारण है, लेकिन इसमें और भी बहुत कुछ है। से के प्रलेखनobject.__hash__(self) :

डिफ़ॉल्ट रूप __hash__()से str, bytesऔर datetimeऑब्जेक्ट्स के मान एक अप्रत्याशित यादृच्छिक मान के साथ "नमकीन" होते हैं। यद्यपि वे एक व्यक्तिगत पायथन प्रक्रिया के भीतर स्थिर रहते हैं, वे पायथन के बार-बार होने वाले आक्रमणों के बीच अनुमानित नहीं हैं।

इसका उद्देश्य सावधानी से चुने गए इनपुट के कारण एक इनकार-सेवा के खिलाफ सुरक्षा प्रदान करना है जो एक तानाशाही प्रविष्टि, ओ (n²) जटिलता के सबसे खराब मामले के प्रदर्शन का शोषण करता है। देखें http://www.ocert.org/advisories/ocert-2011-003.html जानकारी के लिए।

हैश मान बदलने की यात्रा के क्रम को प्रभावित करता है dicts, sets और अन्य मैपिंग। पायथन ने इस आदेश के बारे में कभी गारंटी नहीं दी है (और यह आमतौर पर 32-बिट और 64-बिट बिल्ड के बीच भिन्न होता है)।

यहां तक ​​कि एक ही मशीन पर चलने से चालानों में अलग-अलग परिणाम मिलेंगे:

$ python -c "print(hash('http://stackoverflow.com'))"
-3455286212422042986
$ python -c "print(hash('http://stackoverflow.com'))"
-6940441840934557333

जबकि:

$ python -c "print(hash((1,2,3)))"
2528502973977326415
$ python -c "print(hash((1,2,3)))"
2528502973977326415

पर्यावरण चर भी देखें PYTHONHASHSEED:

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

यदि PYTHONHASHSEEDपूर्णांक मान पर सेट किया जाता है, तो इसका उपयोग hash()हैश यादृच्छिकरण द्वारा कवर किए गए प्रकारों को उत्पन्न करने के लिए एक निश्चित बीज के रूप में किया जाता है ।

इसका उद्देश्य दोहराए गए हैशिंग की अनुमति देना है, जैसे कि दुभाषिया के लिए स्वयं के लिए, या हैश के मूल्यों को साझा करने के लिए अजगर प्रक्रियाओं के एक समूह की अनुमति देना।

पूर्णांक श्रेणी में दशमलव संख्या होनी चाहिए [0, 4294967295]। मान निर्दिष्ट 0करने से हैश यादृच्छिकरण अक्षम हो जाएगा।

उदाहरण के लिए:

$ export PYTHONHASHSEED=0                            
$ python -c "print(hash('http://stackoverflow.com'))"
-5843046192888932305
$ python -c "print(hash('http://stackoverflow.com'))"
-5843046192888932305

3
यह केवल पायथन 3.x के लिए सही है, लेकिन चूंकि पायथन 3 वर्तमान और भविष्य है और यह एकमात्र उत्तर है जो इसे संबोधित करता है, +1।
अलेक्जेंडर हुज़ैग

8

हैश परिणाम 32 बिट और 64 बिट प्लेटफॉर्म के बीच भिन्न होता है

यदि गणना की गई हैश दोनों प्लेटफार्मों का उपयोग करने पर विचार करने के लिए समान होगा

def hash32(value):
    return hash(value) & 0xffffffff

6

एक अनुमान के अनुसार, AppEngine पायथन के 64-बिट कार्यान्वयन का उपयोग कर रहा है (-5768830964305142685 32 बिट्स में फिट नहीं होगा) और पायथन का आपका कार्यान्वयन 32 बिट्स है। आप अलग-अलग कार्यान्वयन के बीच सार्थक रूप से तुलनीय होने वाली वस्तु हैश पर भरोसा नहीं कर सकते।


6

यह हैश फ़ंक्शन है जो Google उत्पादन में अजगर 2.5 के लिए उपयोग करता है:

def c_mul(a, b):
  return eval(hex((long(a) * b) & (2**64 - 1))[:-1])

def py25hash(self):
  if not self:
    return 0 # empty
  value = ord(self[0]) << 7
  for char in self:
    value = c_mul(1000003, value) ^ ord(char)
  value = value ^ len(self)
  if value == -1:
    value = -2
  if value >= 2**63:
    value -= 2**64
  return value

7
क्या आप इस हैश फ़ंक्शन के लिए और क्यों उपयोग किया जाता है, इसके बारे में कोई संदर्भ साझा कर सकते हैं?
amnnabb

5

साइन बिट के बारे में क्या?

उदाहरण के लिए:

हेक्स मूल्य 0xADFE74A5अहस्ताक्षरित 2919134373और हस्ताक्षरित है -1375832923। सही मान पर हस्ताक्षर किए जाने चाहिए (साइन बिट = 1) लेकिन अजगर इसे अहस्ताक्षरित करता है और हमारे पास 64 से 32 बिट के अनुवाद के बाद एक गलत हैश मूल्य है।

सावधान रहें:

def hash32(value):
    return hash(value) & 0xffffffff

3

तार के लिए बहुपद हैश। 1000000009और 239मनमाने ढंग से अभाज्य संख्याएँ हैं। दुर्घटना से टकराव होने की संभावना नहीं है। मॉड्यूलर अंकगणित बहुत तेज नहीं है, लेकिन टकराव को रोकने के लिए यह मोडुलो को एक शक्ति लेने की तुलना में अधिक विश्वसनीय है 2। बेशक, उद्देश्य पर टकराव का पता लगाना आसान है।

mod=1000000009
def hash(s):
    result=0
    for c in s:
        result = (result * 239 + ord(c)) % mod
    return result % mod

2

का मूल्य हैश मानों को प्रारंभ करने के लिए PYTHONHASHSEED के उपयोग किया जा सकता है।

प्रयत्न:

PYTHONHASHSEED python -c 'print(hash('http://stackoverflow.com'))'

-3

यह शायद केवल अपने एल्गोरिथ्म के बजाय ऑपरेटिंग सिस्टम प्रदान किए गए फ़ंक्शन को पूछता है।

जैसा कि अन्य टिप्पणियां कहती हैं, हैशलीब का उपयोग करें या अपना स्वयं का हैश फ़ंक्शन लिखें।

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