একটি অভিধান হ্যাশিং?


156

ক্যাশিংয়ের উদ্দেশ্যে আমাকে জিইটি আর্গুমেন্ট থেকে একটি ক্যাশে কী তৈরি করতে হবে যা ডিকটিতে উপস্থিত রয়েছে।

বর্তমানে আমি ব্যবহার করছি sha1(repr(sorted(my_dict.items())))( sha1()একটি সুবিধার পদ্ধতি যা হ্যাশলিব অভ্যন্তরীণভাবে ব্যবহার করে ) তবে আমি আরও উত্সাহী এর চেয়ে আরও ভাল উপায় থাকলে আমি আগ্রহী।


4
এটি নেস্টেড ডিক্টের সাথে কাজ করতে পারে না। সংক্ষিপ্ত সমাধানটি হ'ল পরিবর্তে json.dumps (আমার_ডিক্ট, সাজানো_কেজগুলি = সত্য) ব্যবহার করুন যা ডিক মানগুলিতে পুনরাবৃত্তি হবে।
আন্দ্রে ফেদোরভ

2
এফওয়াইআই পুনরায়: ডাম্পস, স্ট্যাকওভারফ্লো.com/a/12739361/1082367 বলেছে "ডিকের অনুরূপ কারণের জন্য আচার থেকে আউটপুট আশ্লেষের গ্যারান্টিযুক্ত নয় এবং অর্ডারকে অ-নিয়ন্ত্রক হিসাবে সেট করা হয়। হ্যাশিংয়ের জন্য আচার বা পিপ্রিন্ট বা রেপি ব্যবহার করবেন না Don't । "
ম্যাথু কর্নেল

আইটেম নয়, ডিক কীগুলি বাছাই করুন, আমি কীগুলি হ্যাশ ফাংশনে প্রেরণ করব।
নিউউইচ

2
পরিবর্তনীয় ডেটা স্ট্রাকচার (যেমন অভিধান) হ্যাশিং সম্পর্কে আকর্ষণীয় ব্যাকস্টোরি: পাইথন.অর্গ / দেবদেব / পেপস / পেপ-0351 ইচ্ছামতভাবে জমাটবদ্ধ বস্তুগুলিকে অনুমতি দেওয়ার প্রস্তাব দেওয়া হয়েছিল, তবে প্রত্যাখ্যান করা হয়েছে। যৌক্তিকতার জন্য, পাইথন- ডেভের
mail.python.org/pipermail/python-dev/2006-

যদি আপনার ডেটা জসন ফর্ম্যাট হয় এবং আপনি শব্দার্থগতভাবে আক্রমণাত্মক হ্যাশিং চান, github.com/schollii/sandals/blob/master/json_sem_hash.py চেকআউট করুন । এটি নেস্টেড স্ট্রাকচারগুলিতে (অবশ্যই, জসন থেকে) কাজ করে এবং সংরক্ষণ করা অর্ডারের মতো ডিকের অভ্যন্তরের উপর নির্ভর করে না (যা পাইথনের জীবদ্দশায় বিকশিত হয়েছে) এবং যদি দুটি ডাটা স্ট্রাকচার শব্দার্থতভাবে একই হয় তবে একই হ্যাশ দেবে ( মত {'a': 1, 'b':2}শব্দার্থগতভাবে হিসাবে একই {'b':2, 'a':1})। আমি এটি এখনও খুব জটিল কিছুতে ব্যবহার করি নি তাই ওয়াইএমএমভি তবে প্রতিক্রিয়া স্বাগত।
অলিভার

উত্তর:


110

যদি আপনার অভিধানটি নাস্ট করা না হয় তবে আপনি ডিকের আইটেমগুলি ব্যবহার করে হিমায়িত তৈরি করতে পারেন hash():

hash(frozenset(my_dict.items()))

এটি JSON স্ট্রিং তৈরি করতে বা অভিধানের উপস্থাপনের তুলনায় কম গণনামূলক নিবিড়।

আপডেট: দয়া করে নীচের মন্তব্যগুলি দেখুন, কেন এই পদ্ধতির কোনও স্থির ফলাফল হতে পারে না।


9
এটি নেস্টেড ডিকশনারি নিয়ে আমার পক্ষে কাজ করে না। আমি নীচের সমাধানটি চেষ্টা করে দেখিনি (খুব জটিল)। ওপির সমাধানটি পুরোপুরি সূক্ষ্মভাবে কাজ করে। আমি একটি আমদানি সংরক্ষণ করতে হ্যাশ দিয়ে sha1 প্রতিস্থাপন করেছি।
স্প্যাটেল

9
@ সিলেসার এটি কাজ করবে না কেননা ডুপ্লে অর্ডারের নির্দেশ করে তবে ডিক আইটেমগুলি অর্ডারড হয় না। হিমশীতল আরও ভাল।
এন্টিমোনি

28
কিছু আলাদা মেশিন জুড়ে যদি কোনও সামঞ্জস্য বজায় রাখার প্রয়োজন হয় তবে অন্তর্নির্মিত হ্যাশ থেকে সাবধান থাকুন। হেরোকু এবং জিএই এর মতো ক্লাউড প্ল্যাটফর্মে অজগরটির প্রয়োগগুলি হ্যাশ () এর জন্য বিভিন্ন পরিস্থিতিতে দুটি বা তার বেশি "মেশিন" (হিরকুর ক্ষেত্রে ডায়নোস) এর মধ্যে ভাগ করা আবশ্যক যে কোনও কিছুর জন্য অকেজো হয়ে উঠবে তার বিভিন্ন মান ফিরিয়ে দেবে
বেন রবার্টস

6
এটি আকর্ষণীয় হতে পারে hash()ফাংশনটি একটি স্থিতিশীল আউটপুট উত্পাদন করে না। এর অর্থ হ'ল, একই ইনপুটটি দেওয়া হলে, একই পাইথন ইন্টারপ্রেটারের বিভিন্ন উদাহরণ সহ এটি বিভিন্ন ফলাফল দেয়। আমার কাছে, দেখে মনে হচ্ছে প্রতিবার দোভাষীটি শুরু করার সময় কোনও ধরণের বীজ মান উত্পন্ন হয়।
হারমান স্ক্যাচনার

7
প্রত্যাশিত। সুরক্ষার কারণে বীজটি চালু করা হয়েছে যতক্ষণ না আমি মনে করি একরকম মেমরি র্যান্ডমাইজেশন যুক্ত করা আছে। সুতরাং আপনি দুটি অজগর প্রক্রিয়ার মধ্যে
হ্যাশটি

137

sorted(d.items())আমাদের একটি স্থিতিশীল repr পেতে ব্যবহার করা যথেষ্ট নয়। এর মানগুলির মধ্যে কিছু অভিধানও dহতে পারে এবং তাদের কীগুলি এখনও একটি স্বেচ্ছাসেবী ক্রমে প্রকাশিত হবে। যতক্ষণ না সমস্ত কীগুলি স্ট্রিং থাকে ততক্ষণ আমি ব্যবহার করতে পছন্দ করি:

json.dumps(d, sort_keys=True)

এটি বলেছিল, যদি হ্যাশগুলি বিভিন্ন মেশিন বা পাইথন সংস্করণ জুড়ে স্থিতিশীল হওয়ার প্রয়োজন হয় তবে আমি নিশ্চিত নই যে এটি বুলেটপ্রুফ। ডিফল্টর কোনও পরিবর্তন থেকে নিজেকে রক্ষা করতে আপনি যুক্তি separatorsএবং ensure_asciiযুক্তি যুক্ত করতে চাইতে পারেন । আমি মন্তব্য প্রশংসা করব।


6
এটি কেবল অদ্ভুত হচ্ছে, তবে জেএসওএন বেশিরভাগ অক্ষরকে কোনও আক্ষরিক অব্যাহতি ছাড়াই স্ট্রিংগুলিতে প্রদর্শিত হতে দেয়, সুতরাং এনকোডারটি অক্ষরগুলি থেকে বাঁচতে হবে বা কেবল সেগুলির মধ্য দিয়ে যেতে হবে সে সম্পর্কে কিছু পছন্দ করতে পারে। তারপরে ঝুঁকিটি হ'ল এনকোডারটির বিভিন্ন সংস্করণ (বা ভবিষ্যতের সংস্করণ) ডিফল্টরূপে বিভিন্ন পালানোর পছন্দ করতে পারে এবং তারপরে আপনার প্রোগ্রামটি একই পরিবেশের জন্য একই অভিধানের জন্য বিভিন্ন হ্যাশ মান গণনা করবে। ensure_asciiযুক্তি এই সম্পূর্ণভাবে প্রকল্পিত সমস্যা রক্ষা করবে।
জ্যাক ও'কনর 4

4
আমি বিভিন্ন ডেটাসেট দিয়ে এর পারফরম্যান্স পরীক্ষা করেছি, এটি এর চেয়ে অনেক দ্রুত make_hashgist.github.com/charlax/b8731de51d2ea86c6eb9
চার্লাক্স

3
@ চ্যারলাক্স উজসন ডিক জোড়গুলির ক্রমানুসারে গ্যারান্টি দেয় না, তাই এটি করা নিরাপদ নয়
আর্থার্পার্স

11
এই সমাধানটি কেবল ততক্ষণ কাজ করে যতক্ষণ না সমস্ত কীগুলি স্ট্রিং হয়, যেমন json.dumps ({'a': {(0, 5): 5, 1: 3}}) ব্যর্থ হয়।
কাদে

5
@ লরেঞ্জোবেলি, আপনি কমান্ড যুক্ত default=strকরে তা কাটিয়ে উঠতে পারেন dumps। সুন্দরভাবে কাজ করা লাগে।
mlissner

63

সম্পাদনা : আপনার সমস্ত কী যদি স্ট্রিং হয় , তবে এই উত্তরটি পড়া চালিয়ে যাওয়ার আগে দয়া করে জ্যাক ও'কনোরের উল্লেখযোগ্য সরল (এবং দ্রুত) সমাধানটি দেখুন (যা নেস্টেড অভিধানগুলি হ্যাশিংয়ের জন্যও কাজ করে)।

যদিও একটি উত্তর গৃহীত হয়েছে, তথাপি প্রশ্নের শিরোনাম হ্যাশিং একটি অজগর অভিধান, এবং সেই শিরোনামটি সম্পর্কে উত্তরটি অসম্পূর্ণ। (প্রশ্নের প্রধান হিসাবে, উত্তরটি সম্পূর্ণ is

নেস্টেড ডিকশনারি

যদি কোনও অভিধান কীভাবে হ্যাশ করতে হয় তার জন্য স্ট্যাক ওভারফ্রো অনুসন্ধান করে, কেউ এই উপযুক্তভাবে শিরোনামযুক্ত প্রশ্নের উপর ঝুঁকতে পারে এবং কেউ যদি নেস্টেড ডিকশনারি হ্যাশ করার চেষ্টা করে তবে অসন্তুষ্ট থাকে। উপরের উত্তরটি এই ক্ষেত্রে কাজ করবে না এবং হ্যাশটি পুনরুদ্ধার করতে আপনাকে এক ধরণের পুনরাবৃত্তিমূলক ব্যবস্থা প্রয়োগ করতে হবে।

এখানে একটি যেমন প্রক্রিয়া:

import copy

def make_hash(o):

  """
  Makes a hash from a dictionary, list, tuple or set to any level, that contains
  only other hashable types (including any lists, tuples, sets, and
  dictionaries).
  """

  if isinstance(o, (set, tuple, list)):

    return tuple([make_hash(e) for e in o])    

  elif not isinstance(o, dict):

    return hash(o)

  new_o = copy.deepcopy(o)
  for k, v in new_o.items():
    new_o[k] = make_hash(v)

  return hash(tuple(frozenset(sorted(new_o.items()))))

বোনাস: হ্যাশিং অবজেক্টস এবং ক্লাসেস

hash()ফাংশন কাজ করে মহান যখন আপনি শ্রেণীর বা দৃষ্টান্ত হ্যাশ। যাইহোক, হ্যাশের সাথে আমি খুঁজে পেয়েছি এমন একটি বিষয়, যা বস্তু সম্পর্কিত:

class Foo(object): pass
foo = Foo()
print (hash(foo)) # 1209812346789
foo.a = 1
print (hash(foo)) # 1209812346789

হুশ একই, এমনকি আমি ফু বদলেছি। এটি কারণ ফু এর পরিচয় পরিবর্তন হয়নি, তাই হ্যাশটি একই। যদি আপনি foo এর বর্তমান সংজ্ঞা অনুসারে আলাদাভাবে হ্যাশ করতে চান তবে সমাধানটি হ'ল যা কিছু পরিবর্তন করছে তা হ্যাশ করে দেওয়া। এই ক্ষেত্রে, __dict__বৈশিষ্ট্য:

class Foo(object): pass
foo = Foo()
print (make_hash(foo.__dict__)) # 1209812346789
foo.a = 1
print (make_hash(foo.__dict__)) # -78956430974785

হায়, আপনি যখন ক্লাসে নিজেই একই জিনিসটি করার চেষ্টা করছেন:

print (make_hash(Foo.__dict__)) # TypeError: unhashable type: 'dict_proxy'

শ্রেণীর __dict__সম্পত্তিটি কোনও সাধারণ অভিধান নয়:

print (type(Foo.__dict__)) # type <'dict_proxy'>

এখানে পূর্বের মতো একই ব্যবস্থা রয়েছে যা ক্লাসগুলি যথাযথভাবে পরিচালনা করবে:

import copy

DictProxyType = type(object.__dict__)

def make_hash(o):

  """
  Makes a hash from a dictionary, list, tuple or set to any level, that 
  contains only other hashable types (including any lists, tuples, sets, and
  dictionaries). In the case where other kinds of objects (like classes) need 
  to be hashed, pass in a collection of object attributes that are pertinent. 
  For example, a class can be hashed in this fashion:

    make_hash([cls.__dict__, cls.__name__])

  A function can be hashed like so:

    make_hash([fn.__dict__, fn.__code__])
  """

  if type(o) == DictProxyType:
    o2 = {}
    for k, v in o.items():
      if not k.startswith("__"):
        o2[k] = v
    o = o2  

  if isinstance(o, (set, tuple, list)):

    return tuple([make_hash(e) for e in o])    

  elif not isinstance(o, dict):

    return hash(o)

  new_o = copy.deepcopy(o)
  for k, v in new_o.items():
    new_o[k] = make_hash(v)

  return hash(tuple(frozenset(sorted(new_o.items()))))

আপনি এটি চাইলেও অনেকগুলি উপাদানগুলির একটি হ্যাশ টুপল ফিরে পেতে আপনি এটি ব্যবহার করতে পারেন:

# -7666086133114527897
print (make_hash(func.__code__))

# (-7666086133114527897, 3527539)
print (make_hash([func.__code__, func.__dict__]))

# (-7666086133114527897, 3527539, -509551383349783210)
print (make_hash([func.__code__, func.__dict__, func.__name__]))

দ্রষ্টব্য: উপরের সমস্ত কোড পাইথন 3.x ধরে নিয়েছে। পূর্ববর্তী সংস্করণগুলিতে পরীক্ষা করা হয়নি, যদিও আমি অনুমান করি যে make_hash()এটি কাজ করবে, বলুন, ২.7.২। যতদূর উদাহরণগুলি কাজ করে, আমি এটি জানি

func.__code__ 

সঙ্গে প্রতিস্থাপন করা উচিত

func.func_code

isinstance দ্বিতীয় আর্গুমেন্টের জন্য একটি ক্রম নেয়, সুতরাং isinstance (ও, (সেট, টিপল, তালিকা)) কাজ করবে।
এক্সিলোট

আমাকে অনুধাবন করার জন্য ধন্যবাদ ক্রমাগত হ্যাশ
ক্যোরিস্ট্রিং

1
ডিক আইটেমের ক্রমটি আলাদা হলেও মূল মানগুলি হয় না -> একই হ্যাশ তৈরি করতে আইটেমগুলি বাছাই করা দরকার -> রিটার্ন হ্যাশ (টিপল (ফ্রোজেন্ট (সাজানো (নতুন_ও.ইটেমস ())))
বাস কোপম্যানস

নিস! আমি hashচারপাশে তালিকা এবং টিপলগুলিতে একটি কল যুক্ত করেছি । অন্যথায় এটি আমার সংখ্যার সংখ্যার তালিকাগুলি গ্রহণ করে যা আমার অভিধানে মান হিসাবে বিবেচিত হয় এবং হ্যাশগুলির তালিকা ফিরিয়ে দেয়, যা আমি চাই না।
ওসা

হিমশীতল একটি নিখরচায় সংগ্রহ, সুতরাং এর ইনপুটগুলি বাছাই করে লাভ করার কিছুই নেই। অন্যদিকে তালিকাগুলি এবং টিপলগুলি হ'ল অর্ডারড কালেকশন ("সিকোয়েন্সগুলি"), এবং তাই হ্যাশ মানটি আইটেমের ক্রম দ্বারা প্রভাবিত হওয়া উচিত। আপনি তাদের বাছাই করা উচিত নয়!
রবএম 15

14

এখানে একটি পরিষ্কার সমাধান।

def freeze(o):
  if isinstance(o,dict):
    return frozenset({ k:freeze(v) for k,v in o.items()}.items())

  if isinstance(o,list):
    return tuple([freeze(v) for v in o])

  return o


def make_hash(o):
    """
    makes a hash out of anything that contains only list,dict and hashable types including string and numeric types
    """
    return hash(freeze(o))  

আপনি যদি পরিবর্তিত if isinstance(o,list):হন if isinstance(obj, (set, tuple, list)):তবে এই ফাংশনটি কোনও বস্তুর উপর কাজ করতে পারে।
পিটার শোর্ন

10

নীচের কোডটি পাইথন হ্যাশ () ফাংশনটি ব্যবহার করা এড়িয়ে চলে কারণ এটি পাইথনের পুনঃসূচনাগুলি জুড়ে সামঞ্জস্যপূর্ণ হ্যাশ সরবরাহ করবে না ( পাইথন ৩.৩-এ হ্যাশ ফাংশনটি সেশনের মধ্যে বিভিন্ন ফলাফল দেয় )। make_hashable()বস্তুটিকে নেস্টেড টিপলসে make_hash_sha256()রূপান্তরিত করবে repr()এবং একটি বেস 64 এনকোডেড SHA256 হ্যাশকে রূপান্তর করবে ।

import hashlib
import base64

def make_hash_sha256(o):
    hasher = hashlib.sha256()
    hasher.update(repr(make_hashable(o)).encode())
    return base64.b64encode(hasher.digest()).decode()

def make_hashable(o):
    if isinstance(o, (tuple, list)):
        return tuple((make_hashable(e) for e in o))

    if isinstance(o, dict):
        return tuple(sorted((k,make_hashable(v)) for k,v in o.items()))

    if isinstance(o, (set, frozenset)):
        return tuple(sorted(make_hashable(e) for e in o))

    return o

o = dict(x=1,b=2,c=[3,4,5],d={6,7})
print(make_hashable(o))
# (('b', 2), ('c', (3, 4, 5)), ('d', (6, 7)), ('x', 1))

print(make_hash_sha256(o))
# fyt/gK6D24H9Ugexw+g3lbqnKZ0JAcgtNW+rXIDeU2Y=

1
make_hash_sha256(((0,1),(2,3)))==make_hash_sha256({0:1,2:3})==make_hash_sha256({2:3,0:1})!=make_hash_sha256(((2,3),(0,1)))। এটি আমি যে সমাধানটি সন্ধান করছি এটি পুরোপুরি সমাধান নয় তবে এটি একটি দুর্দান্ত মধ্যবর্তী is আমি type(o).__name__পৃথক পৃথককরণের টিউপসগুলির প্রতিটিটির শুরুতে যুক্ত করার কথা ভাবছি ।
পোইখ

আপনি যদি তালিকাটিও বাছাই করতে চান:tuple(sorted((make_hashable(e) for e in o)))
সুরজ

Make_hash_sha256 () - দুর্দান্ত!
jtlz2

1
@ সুরজ আপনার হ্যাশিংয়ের আগে তালিকাটি বাছাই করা উচিত নয় কারণ যে তালিকাগুলিতে বিভিন্ন অর্ডারে তাদের বিষয়বস্তু রয়েছে তা অবশ্যই একই জিনিস নয়। আইটেমগুলির ক্রম যদি সমস্যা না দেয় তা হ'ল আপনি ভুল ডেটা কাঠামোটি ব্যবহার করছেন। আপনার তালিকার পরিবর্তে একটি সেট ব্যবহার করা উচিত।
স্কটক্লো

@ স্কটক্লো এটা খুব সত্য। এই পয়েন্ট যোগ করার জন্য ধন্যবাদ। এমন দুটি পরিস্থিতি রয়েছে যেখানে আপনি এখনও একটি তালিকা চান (নির্দিষ্ট অর্ডারিংয়ের প্রয়োজন ছাড়াই) - ১. পুনরাবৃত্তি আইটেমগুলির তালিকা। ২. আপনি যখন সরাসরি JSON ব্যবহার করতে পারেন। জেএসএন যেমন "সেট" উপস্থাপনা সমর্থন করে না।
সুরজ

5

২০১৩ এর উত্তর থেকে আপডেট হয়েছে ...

উপরের উত্তরগুলির কোনওটিই আমার কাছে বিশ্বাসযোগ্য বলে মনে হচ্ছে না। কারণ আইটেম () ব্যবহার। আমি যতদূর জানি, এটি একটি মেশিন-নির্ভর ক্রমে প্রকাশিত হয়।

এর পরিবর্তে কীভাবে?

import hashlib

def dict_hash(the_dict, *ignore):
    if ignore:  # Sometimes you don't care about some items
        interesting = the_dict.copy()
        for item in ignore:
            if item in interesting:
                interesting.pop(item)
        the_dict = interesting
    result = hashlib.sha1(
        '%s' % sorted(the_dict.items())
    ).hexdigest()
    return result

আপনি কেন মনে dict.itemsকরেন যে এটি এমন বিষয় যা পূর্বাভাসে অর্ডার করা তালিকাকে ফেরত দেয় না? frozensetএর যত্ন নেয়
গ্লাররাইন

2
সংজ্ঞা অনুসারে একটি সেট আনর্ডারড হয়। সুতরাং অবজেক্টগুলিতে যে ক্রম যুক্ত হয় তা অপ্রাসঙ্গিক। আপনাকে বুঝতে হবে যে বিল্ট-ইন ফাংশনটি hashকীভাবে হিমায়িত বিষয়বস্তু প্রিন্ট করা হয় বা এ জাতীয় কিছুতে চিন্তা করে না। এটি বেশ কয়েকটি মেশিন এবং পাইথন সংস্করণে পরীক্ষা করুন এবং আপনি দেখতে পাবেন।
glarrain

আপনি মান = হ্যাশ ('% s ::% s'% (মান, প্রকার (মান))) কেন অতিরিক্ত হ্যাশ () কল ব্যবহার করবেন ??
রুইডো

4

কী অর্ডার সংরক্ষণের জন্য hash(str(dictionary))বা তার পরিবর্তে hash(json.dumps(dictionary))আমি দ্রুত এবং নোংরা সমাধানটি পছন্দ করি:

from pprint import pformat
h = hash(pformat(dictionary))

এটি এমন ধরণের DateTimeএবং আরও বেশি যা জেএসওএন সিরিয়ালাইজযোগ্য নয় তার জন্যও কাজ করবে ।


3
কে এই গ্যারান্টি দেয় যে ফর্ম্যাট বা জসন সর্বদা একই ক্রম ব্যবহার করে?
চোরমাস্টার

1
@ থিফমাস্টার, "সংস্করণ ২.২ এ পরিবর্তিত হয়েছে: ডিসপ্লেটি গণনা করার আগে অভিধানগুলি কী অনুসারে বাছাই করা হয়; 2.5 এর আগে, একটি ডিকশনারি কেবল তখনই সাজানো হত যদি এর ডকুমেন্টটি লিখিত না হলেও এটির জন্য একাধিক লাইনের প্রয়োজন হত।" ( ডকস.পিথন)। org / 2 / লাইব্রেরি / pprint.html )
আরেল

2
এটি আমার কাছে বৈধ বলে মনে হচ্ছে না। পি-প্রিন্ট মডিউল এবং ফর্ম্যাটটি লেখকরা প্রদর্শনের উদ্দেশ্যে এবং সিরিয়ালাইজেশন নয় বলে বোঝে। এ কারণে, আপনার ধারণাটি গ্রহণ করা আপনার নিরাপদ বোধ করা উচিত নয় যে ফর্ম্যাটটি সর্বদা কাজের ক্ষেত্রে ঘটে এমন কোনও ফলাফল ফিরে আসবে।
ডেভিড স্যান্ডার্স 22

3

আপনি তৃতীয় পক্ষের frozendictমডিউলটি আপনার ডিককে হিমশীতল করতে এবং এটিকে হ্যাশেবল করতে সক্ষম করতে পারেন।

from frozendict import frozendict
my_dict = frozendict(my_dict)

নেস্টেড বস্তুগুলি পরিচালনা করার জন্য, আপনি এগুলি দিয়ে যেতে পারেন:

import collections.abc

def make_hashable(x):
    if isinstance(x, collections.abc.Hashable):
        return x
    elif isinstance(x, collections.abc.Sequence):
        return tuple(make_hashable(xi) for xi in x)
    elif isinstance(x, collections.abc.Set):
        return frozenset(make_hashable(xi) for xi in x)
    elif isinstance(x, collections.abc.Mapping):
        return frozendict({k: make_hashable(v) for k, v in x.items()})
    else:
        raise TypeError("Don't know how to make {} objects hashable".format(type(x).__name__))

আপনি যদি আরও প্রকারের সমর্থন করতে চান তবে functools.singledispatch(পাইথন ৩.7) ব্যবহার করুন :

@functools.singledispatch
def make_hashable(x):
    raise TypeError("Don't know how to make {} objects hashable".format(type(x).__name__))

@make_hashable.register
def _(x: collections.abc.Hashable):
    return x

@make_hashable.register
def _(x: collections.abc.Sequence):
    return tuple(make_hashable(xi) for xi in x)

@make_hashable.register
def _(x: collections.abc.Set):
    return frozenset(make_hashable(xi) for xi in x)

@make_hashable.register
def _(x: collections.abc.Mapping):
    return frozendict({k: make_hashable(v) for k, v in x.items()})

# add your own types here

এটি কাজ করে না, উদাহরণস্বরূপ, dictকিছু DataFrameবস্তুর জন্য।
জেমস হিরশর্ন

@ জেমসহির্সকর্ন: জোরে জোরে ব্যর্থ হতে আপডেট হয়েছে
এরিক

উত্তম! elifএটির সাথে কাজ করার জন্য আমি নিম্নলিখিত ধারাটি যুক্ত করেছি DataFrame: elif isinstance(x, pd.DataFrame): return make_hashable(hash_pandas_object(x).tolist()) আমি উত্তরটি সম্পাদনা করব এবং আপনি এটি গ্রহণ করেন কিনা তা দেখুন ...
জেমস হিরশর্ন

1
ঠিক আছে. আমি দেখতে পাচ্ছি যে আমি "হ্যাশেবল" এর চেয়ে বেশি কিছু চাইছিলাম, যা কেবল গ্যারান্টি দেয় যে সমান বস্তুগুলির একই হ্যাশ থাকবে। আমি .. ইত্যাদি একটি সংস্করণ যে রান মধ্যে একই মান দিতে হবে কাজ করছি, এবং পাইথন সংস্করণের স্বাধীন,
জেমস Hirschorn

1
hashর্যান্ডমাইজেশন ইচ্ছাকৃত সুরক্ষা বৈশিষ্ট্যটি পাইথন ৩.7 এ ডিফল্টরূপে সক্ষম করা হয়েছে।
এরিক

1

এটি করার জন্য আপনি মানচিত্রের গ্রন্থাগারটি ব্যবহার করতে পারেন । বিশেষত, মানচিত্র.ফ্রোজেনম্যাপ

import maps
fm = maps.FrozenMap(my_dict)
hash(fm)

ইনস্টল করতে maps, কেবল করুন:

pip install maps

এটি নেস্টেড কেসটিও পরিচালনা করে dict:

import maps
fm = maps.FrozenMap.recurse(my_dict)
hash(fm)

দাবি অস্বীকার: আমি mapsগ্রন্থাগারের লেখক ।


গ্রন্থাগারটি কোনও ডিকের মধ্যে তালিকাটি সাজান না। এবং তাই এটি বিভিন্ন হ্যাশ উত্পাদন করতে পারে। একটি তালিকাও বাছাই করার বিকল্প থাকতে হবে। হিমশৈলীর সাহায্য করা উচিত, তবে আমি অবাক হই যে আপনি কীভাবে একটি নেস্টেড ডিক্টের সাথে ডিক্টের একটি তালিকাযুক্ত মামলাটি পরিচালনা করবেন। যেমন ডিক অদৃশ্য হয়।
সুরজ

1
@ সুরজ: এটি নেস্টেড কাঠামোর মাধ্যমে পরিচালনা করে.recurseমানচিত্র.ড্রেডশেডস.আইও / এএন / স্লেস্ট / এপি.ইচ.টি.এম.এল.টি.এমএল.ম্যাপস.ফ্রোজেনম্যাপ.রেক্রুস দেখুন । তালিকাগুলিতে অর্ডার দেওয়া শব্দার্থগত অর্থবোধক, আপনি যদি আদেশের স্বাধীনতা চান তবে আপনি কলিংয়ের আগে আপনার তালিকাগুলিকে সেটগুলিতে রূপান্তর করতে পারেন .recurse। আপনি (.eg ) এর চেয়ে পৃথক হ্যাশযোগ্য ডেটা স্ট্রাকচার ব্যবহার list_fnকরতে প্যারামিটারটি ব্যবহার করতে পারেন.recursetuplefrozenset
পেড্রো ক্যাটোরি

0

সমস্যার কাছে যাওয়ার একটি উপায় হ'ল অভিধানের আইটেমগুলির একটি বিশৃঙ্খলা তৈরি করা:

hash(tuple(my_dict.items()))

-8

আমি এটি এইভাবে করি:

hash(str(my_dict))

1
এই পদ্ধতিতে কী ভুল তা কেউ ব্যাখ্যা করতে পারেন?
mhristache

7
@ ম্যাক্সিমি ডিকোচারগুলি স্থিতিশীল নয় এটি শৃঙ্খলা সংক্রান্ত শর্তাদি, সুতরাং hash(str({'a': 1, 'b': 2})) != hash(str({'b': 2, 'a': 1}))(এটি কিছু অভিধানের জন্য কাজ করতে পারে, এটি সকলের পক্ষে কাজ করার গ্যারান্টিযুক্ত নয়)।
ভ্লাদ ফ্রোলভ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.