it-swarm.asia

ماذا يفعل التجزئة في الثعبان؟

رأيت مثالًا على الكود حيث يتم تطبيق دالة hash على Tuple. نتيجة لذلك تقوم بإرجاع عدد صحيح سالب. وأتساءل ماذا تفعل هذه الوظيفة. جوجل لا يساعد. لقد عثرت على صفحة تشرح كيفية حساب التجزئة ، لكنها لا توضح سبب حاجتنا لهذه الوظيفة.

59
Roman

التجزئة هي عدد صحيح ثابت يحدد قيمة معينة . يجب أن يكون لكل قيمة علامة تجزئة خاصة بها ، لذلك بنفس القيمة ، ستحصل على علامة التجزئة نفسها حتى لو لم تكن نفس العنصر.

>>> hash("Look at me!")
4343814758193556824
>>> f = "Look at me!"
>>> hash(f)
4343814758193556824

يجب إنشاء قيم تجزئة بطريقة يتم توزيع القيم الناتجة بالتساوي لتقليل عدد تصادمات التجزئة التي تحصل عليها. تصادمات التجزئة تكون عندما يكون لقيمتين مختلفتين نفس التجزئة. لذلك ، غالباً ما تؤدي التغييرات الصغيرة نسبيًا إلى تجزئة مختلفة تمامًا.

>>> hash("Look at me!!")
6941904779894686356

هذه الأرقام مفيدة للغاية ، لأنها تتيح البحث السريع عن القيم في مجموعة كبيرة من القيم. مثالان على استخدامها هما set و Python و dict. في list ، إذا كنت تريد التحقق مما إذا كانت هناك قيمة في القائمة ، مع if x in values: ، فيجب على Python الانتقال إلى القائمة بأكملها ومقارنة x بكل قيمة في القائمة values. قد يستغرق هذا وقتًا طويلاً list. في set ، تقوم Python بتتبع كل تجزئة ، وعندما تكتب if x in values: ، ستحصل Python على قيمة التجزئة لـ x ، ابحث عن ذلك في بنية داخلية ثم قارن x فقط مع القيم التي لها نفس التجزئة مثل _x.

يتم استخدام نفس المنهجية للبحث القاموس. هذا يجعل البحث في set و dict سريعًا للغاية ، في حين أن البحث في list يكون بطيئًا. هذا يعني أيضًا أنه يمكن أن يكون لديك كائنات غير قابلة للتجزئة في list ، ولكن ليس في set أو كمفاتيح في dict. المثال النموذجي للكائنات غير القابلة للتجزئة هو أي كائن قابل للتغيير ، مما يعني أنه يمكنك تغيير قيمته. إذا كان لديك كائن قابل للتغيير ، فلا ينبغي أن يكون قابلاً للتجزئة ، حيث سيتغير عنصر التجزئة الخاص به بعد ذلك طوال فترة حياته ، مما قد يتسبب في كثير من الالتباس ، حيث يمكن أن ينتهي الكائن تحت قيمة التجزئة غير الصحيحة في القاموس.

لاحظ أن تجزئة القيمة تحتاج فقط إلى أن تكون متشابهة لتشغيل Python واحد. في بيثون 3.3 سوف يتغيرون في الواقع لكل رمية جديدة من بيثون:

$ /opt/python33/bin/python3
Python 3.3.2 (default, Jun 17 2013, 17:49:21) 
[GCC 4.6.3] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> hash("foo")
1849024199686380661
>>> 
$ /opt/python33/bin/python3
Python 3.3.2 (default, Jun 17 2013, 17:49:21) 
[GCC 4.6.3] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> hash("foo")
-7416743951976404299

هذا الأمر يصعب تخمين قيمة التجزئة التي ستحصل عليها سلسلة معينة ، وهي ميزة أمان مهمة لتطبيقات الويب وما إلى ذلك.

لذلك يجب عدم تخزين قيم التجزئة بشكل دائم. إذا كنت بحاجة إلى استخدام قيم التجزئة بطريقة دائمة ، يمكنك إلقاء نظرة على الأنواع الأكثر "خطورة" من التجزئات ، و وظائف تجزئة التشفير ، والتي يمكن استخدامها لإجراء عمليات التحقق من الملفات القابلة للتحقق منها ، إلخ.

106
Lennart Regebro

TL، DR:

يرجى الرجوع إلى المسرد : ___ يستخدم hash() كاختصار لمقارنة الكائنات ، ويعتبر الكائن قابلًا للتجزئة إذا كان يمكن مقارنته بالكائنات الأخرى. هذا هو السبب في أننا نستخدم hash(). كما أنه يستخدم للوصول إلى dict و set والتي يتم تنفيذها على أنها يمكن تغيير حجم جداول التجزئة في CPython .

اعتبارات فنية

  • عادة ما تكون مقارنة الكائنات (والتي قد تتضمن عدة مستويات من العودية) باهظة الثمن.
  • من المفضل أن تكون الدالة hash() بترتيب من حيث الحجم (أو عدة) أقل تكلفة.
  • تعتبر مقارنة جزئين أسهل من مقارنة كائنين ، وهذا هو المكان الذي يوجد فيه الاختصار.

إذا قرأت عن كيفية تنفيذ القواميس ، فإنها تستخدم جداول التجزئة ، مما يعني أن استخلاص مفتاح من كائن هو حجر الزاوية لاسترداد الكائنات في القواميس في O(1). هذا يعتمد بشكل كبير على وظيفة التجزئة الخاصة بك لتكون مقاومة التصادم . أسوأ حالة للحصول على عنصر في القاموس هو في الواقع O(n).

في هذه المذكرة ، الكائنات القابلة للتغيير عادة ما تكون غير قابلة للتجزئة. الخاصية hashable يعني أنه يمكنك استخدام كائن كمفتاح. إذا تم استخدام قيمة التجزئة كمفتاح وتغيير محتويات ذلك الكائن نفسه ، فما الذي يجب أن تُرجع دالة التجزئة إليه؟ هل هو نفس المفتاح أم مختلف؟ يعتمد على كيفية تحديد وظيفة التجزئة الخاصة بك.

التعلم بالقدوة:

تخيل أن لدينا هذه الفئة:

>>> class Person(object):
...     def __init__(self, name, ssn, address):
...         self.name = name
...         self.ssn = ssn
...         self.address = address
...     def __hash__(self):
...         return hash(self.ssn)
...     def __eq__(self, other):
...         return self.ssn == other.ssn
... 

يرجى ملاحظة: يعتمد كل ذلك على افتراض أن SSN لا تتغير أبدًا بالنسبة للفرد (لا أعرف حتى من أين يمكن التحقق من هذه الحقيقة بالفعل من مصدر موثوق).

ولدينا بوب:

>>> bob = Person('bob', '1111-222-333', None)

بوب يذهب لرؤية القاضي لتغيير اسمه:

>>> jim = Person('jim bo', '1111-222-333', 'sf bay area')

وهذا هو ما نعرفه:

>>> bob == jim
True

ولكن هذان هما كائنان مختلفان مع ذاكرة مختلفة مخصصة ، تماما مثل اثنين من سجلات مختلفة للشخص نفسه:

>>> bob is jim
False

الآن يأتي الجزء الذي يكون فيه hash () مفيدًا:

>>> dmv_appointments = {}
>>> dmv_appointments[bob] = 'tomorrow'

خمين ما:

>>> dmv_appointments[jim] #?
'tomorrow'

من سجلين مختلفين ، يمكنك الوصول إلى نفس المعلومات. جرب الآن هذا:

>>> dmv_appointments[hash(jim)]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 9, in __eq__
AttributeError: 'int' object has no attribute 'ssn'
>>> hash(jim) == hash(hash(jim))
True

ماذا حدث للتو؟ هذا تصادم. نظرًا لأن hash(jim) == hash(hash(jim)) - وهما كلاهما عدد صحيح من وزن الجسم ، فإننا نحتاج إلى مقارنة إدخال __getitem__ بجميع العناصر التي تصطدم. لا يحتوي المضمّن int على سمة ssn لذلك رحلات.

>>> del Person.__eq__
>>> dmv_appointments[bob]
'tomorrow'
>>> dmv_appointments[jim]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: <__main__.Person object at 0x7f611bd37110>

في هذا المثال الأخير ، أظهر أنه حتى مع الاصطدام ، يتم إجراء المقارنة ، الكائنات لم تعد متساوية ، مما يعني أنها ترفع بنجاح KeyError.

25
dnozay

The Python مستندات hash() state:

قيم التجزئة هي أعداد صحيحة. يتم استخدامها لمقارنة مفاتيح القاموس بسرعة أثناء بحث القاموس.

يتم تطبيق قواميس بايثون كجداول تجزئة. لذلك في أي وقت تستخدم فيه القاموس ، يتم استدعاء hash() على المفاتيح التي تمررها للواجب ، أو البحث.

بالإضافة إلى ذلك ، مستندات لنوع dict الحالة:

لا يجوز استخدام القيم التي ليست hashable ، أي القيم التي تحتوي على قوائم أو قواميس أو أنواع قابلة للتغيير (تتم مقارنتها بالقيمة بدلاً من هوية الكائن) كمفاتيح.

2
Jonathon Reinhart

يتم استخدام التجزئة من قواميس ومجموعات للبحث بسرعة عن الكائن. نقطة انطلاق جيدة هي مقالة ويكيبيديا على جداول التجزئة .

1
NPE

أنا أيضا أبحث عن ذلك منذ وقت طويل جدا ، والآن حصلت على إجابتي لذلك القص معك جميعا ...

يرجى استخدام القاموس نوع البيانات في الثعبان ، جدا جدا التشبيه إلى التجزئة ... لها أيضا دعم متداخلة ، مماثلة ل إلى التجزئة المتداخلة.

مثال:-

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School" # Add new entry

print ("dict['Age']: ", dict['Age'])
print ("dict['School']: ", dict['School'])

نوع بيانات القاموس: - https://www.tutorialspoint.com/python3/python_dictionary.htm

تأمل في حل المشكلة ..

0
HateStackOverFlow