해싱 사전?
캐싱을 위해 dict에 있는 GET 인수에서 캐시 키를 생성해야 합니다.
현재 사용하고 있습니다.sha1(repr(sorted(my_dict.items()))) )sha1()hashlib을 내부적으로 사용하는 편리한 방법인데 더 좋은 방법이 있을까요?
「」를 사용합니다.sorted(d.items())에 있는 값의 d사전일 수도 있지만 키는 여전히 임의의 순서로 나옵니다.모든 키가 문자열인 경우 다음을 사용하는 것이 좋습니다.
json.dumps(d, sort_keys=True)
단, 해시가 다른 머신이나 Python 버전에 걸쳐 안정성이 필요한 경우 방탄인지 확실하지 않습니다. 하면 '어울리지 '를.separators ★★★★★★★★★★★★★★★★★」ensure_ascii기본값이 변경되지 않도록 사용자를 보호하기 위한 인수입니다.댓글 달아주시면 감사하겠습니다.
사전이 중첩되지 않은 경우 dict 항목을 사용하여 frozenset을 만들고 다음을 사용할 수 있습니다.
hash(frozenset(my_dict.items()))
이것은 사전의 JSON 문자열이나 표현을 생성하는 것보다 계산 부하가 훨씬 낮습니다.
업데이트: 이 접근 방식이 안정적인 결과를 가져오지 못하는 이유에 대한 아래 의견을 참조하십시오.
편집: 모든 키가 문자열인 경우 이 답변을 계속 읽기 전에 Jack O'Connor의 매우 심플한(더 빠른) 솔루션을 참조하십시오(네스트된 사전을 해싱하는 데도 사용 가능).
답변은 접수되었지만 질문의 제목은 "Hashing a python dictionary"로 답변이 불완전합니다.(질문 본문에 대해서는 답변이 완료되었습니다.)
중첩된 사전
스택 오버플로를 검색하여 사전을 해시하는 방법을 검색하면 적절한 제목의 이 질문이 발견되어 중첩된 사전을 해시하려고 하면 만족하지 못할 수 있습니다.이 경우 위의 답변은 작동하지 않으므로 해시를 검색하려면 일종의 재귀 메커니즘을 구현해야 합니다.
이러한 메커니즘의 1가지를 다음에 나타냅니다.
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의 아이덴티티가 변경되지 않았기 때문에 해시가 동일하기 때문입니다.현재 정의에 따라 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.하고 있습니다.만, Python 3.x는 되지 않았습니다.이전 버전에서는 테스트되지 않았습니다만,make_hash()예를 들어 2.7.2로 동작합니다.그 사례들이 효과가 있는 한, 나는 확실히 알고 있다.
func.__code__
로 대체해야 한다.
func.func_code
아래 코드는 Python hash() 함수의 사용을 회피하고 있습니다.이는 Python의 재시작 간에 일관된 해시를 제공하지 않기 때문입니다(Python 3.3의 해시 함수는 세션 간에 다른 결과를 반환합니다). make_hashable() 및 "tuples"로 합니다.make_hash_sha256() will will convert convert the the the the the the 도 변환됩니다.repr()Base64의 SHA256의 SHA256의 Base64.
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=
여기 더 명확한 해결책이 있다.
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))
MD5 해시
저에게 가장 안정적인 결과를 가져온 방법은 md5 hashes와 json.stringify를 사용한 것입니다.
from typing import Dict, Any
import hashlib
import json
def dict_hash(dictionary: Dict[str, Any]) -> str:
"""MD5 hash of a dictionary."""
dhash = hashlib.md5()
# We need to sort arguments so {'a': 1, 'b': 2} is
# the same as {'b': 2, 'a': 1}
encoded = json.dumps(dictionary, sort_keys=True).encode()
dhash.update(encoded)
return dhash.hexdigest()
한편, 「 」는, 「 」, 「 」의 사이에hash(frozenset(x.items()) ★★★★★★★★★★★★★★★★★」hash(tuple(sorted(x.items()))모든 키와 값의 쌍을 할당하고 복사하는 작업을 많이 합니다.해시 함수는 많은 메모리 할당을 피할 수 있습니다.
이데올로기 때문에대부분의 해시 함수의 문제는 순서가 중요하다고 가정한다는 것입니다.순서가 없는 구조를 해시하려면 교환 연산이 필요합니다.은 어떤 전체 0.0인 잘. 단위& ★★★★★★★★★★★★★★★★★」|addition xor의 두 좋은.
from functools import reduce
from operator import xor
class hashable(dict):
def __hash__(self):
return reduce(xor, map(hash, self.items()), 0)
# Alternative
def __hash__(self):
return sum(map(hash, self.items()))
xor는 1점: xor는 어느 정도 .dict키는 일의임을 보증합니다.Python python python python python python python python python python python python python python python python python python python python python python python python python python python python python python.
총액 xor의 경우{a}와 같은 값으로 해시됩니다.{a, a, a}x ^ x ^ x = x.
SHA의 보증이 정말로 필요한 경우, 이 방법은 도움이 되지 않습니다.그러나 사전을 세트로 사용하는 경우, 이것은 정상적으로 동작합니다.Python 컨테이너는 몇 가지 충돌에 대해 복원력이 있으며 기본 해시 함수는 매우 좋습니다.
2013년 답변에서 업데이트...
위의 답변 중 어느 것도 신뢰할 수 있는 답변은 없는 것 같습니다.그 이유는 아이템()의 사용 때문입니다.제가 알기로는 기계 의존적인 순서로 나오는 걸로 알고 있습니다.
대신 이건 어때요?
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
순서를 하려면 , 「」가 아닌 「키 순서」를 사용합니다.hash(str(dictionary)) ★★★★★★★★★★★★★★★★★」hash(json.dumps(dictionary))저는 신속하고 더러운 솔루션을 선호합니다.
from pprint import pformat
h = hash(pformat(dictionary))
도 쓸 수요.DateTimeJSON 시리얼화되지 않은 것들도 있습니다.
이를 위해 지도 라이브러리를 사용할 수 있습니다.특히, 지도.프로즌 맵
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★★★★★★★★★★★★★★★★★★.
서드파티 모듈을 사용하여 dict를 동결하고 해시 가능 상태로 만들 수 있습니다.
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 (피톤 3.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
DeepDiff 모듈의 DeepHash 사용
from deepdiff import DeepHash
obj = {'a':'1',b:'2'}
hashes = DeepHash(obj)[obj]
이 스레드의 해싱 함수는 에 의해 머신마다 결과가 다르기 때문에 업투표율이 가장 높은 스레드로부터의 응답은 기능하지 않습니다.
저는 이 스레드의 힌트를 모두 조정하여 저에게 맞는 해결책을 생각해 냈습니다.
import collections
import hashlib
import json
def simplify_object(o):
if isinstance(o, dict):
ordered_dict = collections.OrderedDict(sorted(o.items()))
for k, v in ordered_dict.items():
v = simplify_object(v)
ordered_dict[str(k)] = v
o = ordered_dict
elif isinstance(o, (list, tuple, set)):
o = [simplify_object(el) for el in o]
else:
o = str(o).strip()
return o
def make_hash(o):
o = simplify_object(o)
bytes_val = json.dumps(o, sort_keys=True, ensure_ascii=True, default=str)
hash_val = hashlib.sha1(bytes_val.encode()).hexdigest()
return hash_val
이 문제에 접근하는 한 가지 방법은 사전 항목을 튜플하는 것입니다.
hash(tuple(my_dict.items()))
이것은 일반적인 솔루션이 아닙니다(즉, dict가 중첩되지 않은 경우에만 3가지 방식으로 작동합니다). 하지만 여기에 아무도 제안하지 않았기 때문에 공유하면 유용할 것 같습니다.
(서드파티제의) 불변 패키지를 사용하여 다음과 같은 dict의 불변 '스냅샷'을 생성할 수 있습니다.
from immutables import Map
map = dict(a=1, b=2)
immap = Map(map)
hash(immap)
이것은, 예를 들면, 원래의 dict의 문자열화보다 빠른 것 같습니다.
저는 이 좋은 기사를 통해 이 사실을 알게 되었습니다.
저는 이렇게 합니다.
hash(str(my_dict))
언급URL : https://stackoverflow.com/questions/5884066/hashing-a-dictionary
'source' 카테고리의 다른 글
| jQuery 직렬화된 폼을 PHP 직렬화 해제하려면 어떻게 해야 합니까? (0) | 2022.10.22 |
|---|---|
| 날짜에 하루 추가 (0) | 2022.10.22 |
| Java에서 정적 메서드를 덮어쓰고 오버로드할 수 있습니까? (0) | 2022.10.22 |
| 컬렉션여러 필드로 정렬하다 (0) | 2022.10.22 |
| 어떻게 개발 LAMP 서버에서 여러 버전의 PHP 5.x를 실행할 수 있습니까? (0) | 2022.10.22 |