2011-06-10 5 views
44

필자는 Python에서 powerset 함수를 구현하는 방법을 자세히 설명한 블로그 게시물을 발견했습니다. 그래서 저는 제 자신의 방식대로 시도해 보았습니다. 파이썬은 세트가 해시 가능하지 않기 때문에 분명히 세트를 가질 수 없다는 것을 발견했습니다. powerset의 정의는 집합의 집합이므로 실제 집합 연산을 사용하여 구현하고 싶었 기 때문에 이것은 귀찮은 일입니다.파이썬이 해시 가능으로 설정되지 않는 이유는 무엇입니까?

>>> set([ set() ]) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unhashable type: 'set' 

파이썬 세트가 해시 가능하지 않은 이유가 있습니까?

+3

일반적으로 변경할 수없는 것이면 잘못된 키가됩니다. 튜플을 사용해야하는 경우 사용할 수 있습니다. –

답변

81

일반적으로 불변 객체 만 파이썬에서 해시 가능합니다. set() - frozenset()의 변종은 해시 가능합니다. 파이썬 문서에서

+5

그리고 파이썬 FAQ 항목 [왜 사전 키는 불변일까요?] (http://docs.python.org/3.3/faq/design)을보십시오.html # why-must-dictionary-keys-be-immutable). – abarnert

22

변경 가능하기 때문입니다.

해시 가능하다면 해시는 자동으로 "유효하지 않은"상태가되어 해시가 무의미해질 수 있습니다.

15

:

해쉬
객체는 의 수명 동안 을 변경하지 해시 값이있는 경우 (그것이 해시() 메소드를 필요로) 해쉬입니다 다른 객체와 비교할 수 있습니다 ( eq() 또는 cmp() 메소드가 필요함). 동일한 을 비교하는 Hashable 개체는 동일한 해시 값을 가져야합니다. 이러한 데이터 구조는 내부적 해시 값을 사용하기 때문에

Hashability 는 사전 키 세트의 부재로서 사용할 오브젝트를 만든다. (예 : 목록 또는 사전 등)에는 가변 용기가되어 있지 않은

내장 객체 파이썬의 불변의 모든

은, 해쉬 있습니다. 의 사용자 정의 클래스 인스턴스는 기본적으로 입니다. 그들은 모두 과 같지 않으며 해시 값은 id()입니다.

4

경우이 도움이 ... 당신은 정말 이런 식으로 뭔가 할 수있는 몇 가지 이유 해쉬 등가물로 unhashable 일을 변환해야하는 경우 :

from collections import Hashable, MutableSet, MutableSequence, MutableMapping 

def make_hashdict(value): 
    """ 
    Inspired by https://stackoverflow.com/questions/1151658/python-hashable-dicts 
    - with the added bonus that it inherits from the dict type of value 
     so OrderedDict's maintain their order and other subclasses of dict() maintain their attributes 
    """ 
    map_type = type(value) 

    class HashableDict(map_type): 
     def __init__(self, *args, **kwargs): 
      super(HashableDict, self).__init__(*args, **kwargs) 
     def __hash__(self): 
      return hash(tuple(sorted(self.items()))) 

    hashDict = HashableDict(value) 

    return hashDict 


def make_hashable(value): 
    if not isinstance(value, Hashable): 
     if isinstance(value, MutableSet): 
      value = frozenset(value) 
     elif isinstance(value, MutableSequence): 
      value = tuple(value) 
     elif isinstance(value, MutableMapping): 
      value = make_hashdict(value) 

     return value 

my_set = set() 
my_set.add(make_hashable(['a', 'list'])) 
my_set.add(make_hashable({'a': 1, 'dict': 2})) 
my_set.add(make_hashable({'a', 'new', 'set'})) 

print my_set 

내 HashableDict 구현이 간단하고 최소한 엄격한입니다 예 : here. 산세 등을 지원하는 고급 HashableDict가 필요한 경우 다른 많은 구현을 확인하십시오. 위 버전에서 OrderedDicts의 순서를 유지하면서 원본 dict 클래스를 유지하려고했습니다. 나는 또한 속성과 같은 접근을 위해 here에서 AttrDict를 사용한다.

위의 예는 어떤 방식 으로든 권위있는 것이 아니며 세트의 일부 항목을 저장해야하고 비슷한 항목을 먼저 저장해야하는 비슷한 문제에 대한 나의 해결책입니다.

관련 문제