목록을 python에서 dict 키로 사용할 수 없는 이유는 무엇입니까?사용할 수 있는 것과 사용할 수 없는 것이 정확히 무엇이고, 그 이유는 무엇입니까?
다음 사항이 모두 유효하다는 것을 알게 되었습니다.
>>> d = {}
>>> d[None] = 'foo'
>>> d[(1, 3)] = 'baz'
모듈도 딕트 키로 사용할 수 있습니다.
>>> import sys
>>> d[sys] = 'bar'
단, 목록을 포함하는 튜플은 다음 작업을 수행할 수 없습니다.
>>> d[[2]] = 'spam'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> d[(1, [3])] = 'qux'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
왜 목록을 태플 안에 저장하는 것은 더 이상 딕트 키가 될 수 없다는 것을 의미합니까? 안에 을 쉽게 수 .sys.path
을 사용하다)
열쇠는 '해시 가능'해야 한다는 막연한 생각이 들었지만, 이것이 무엇을 의미하는지, 왜 그런 제한이 있는지 자세히 이해하지 못했습니다.예를 들어 Python이 메모리 위치를 해시로 사용하는 등 목록을 키로 사용하는 것을 허용한다면 무엇이 잘못될까요?
Python Wiki에 이 주제에 대한 좋은 기사가 있습니다.목록이 사전 키가 될 수 없는 이유.여기서 설명한 바와 같이:
예를 들어 Python이 메모리 위치를 해시로 사용하는 등 목록을 키로 사용하는 것을 허용한다면 무엇이 잘못될까요?
을 사용법목록은 일반적으로 내용 값에서 파생된 값으로 간주됩니다(예: (내) 동등성 확인).할 수 할 것이다.[1, 2]
같은 키를 얻으려면 똑같은 목록 오브젝트를 가지고 있어야 합니다.그러나 키로 사용되는 목록을 수정하는 즉시 값별 검색이 중단되며, ID별 검색에서는 해당 목록 개체를 정확하게 추적해야 합니다. 이는 목록 작업을 위한 일반적인 요구사항이 아닙니다.
이나 " " " ( " ) 등 object
더 크게 으로 두 개의 인 '모듈 오브젝트'가 입니까).sys
을 사용하다따라서, 딕트 키로 사용되었을 때, 그러한 경우에서도 아이덴티티로 비교되는 것은 별로 놀랍지 않거나 심지어 예상조차 할 수 없다.
목록을 python에서 dict 키로 사용할 수 없는 이유는 무엇입니까?
>>> d = {repr([1,2,3]): 'value'}
{'[1, 2, 3]': 'value'}
(이 문제를 회피할 방법을 찾고 있는 사람에게)
여기 있는 다른 사람들이 설명하듯이, 당신은 정말로 그럴 수 없습니다.그러나 목록을 사용하려면 문자열 표현을 대신 사용할 수 있습니다.
목록을 태플로 변환할 수 있으며, 태플은 딕트 키로 사용할 수 있습니다.
d = {tuple([1,2,3]): 'value'}
문제는 튜플은 불변하고 리스트는 불변이라는 것입니다.다음 예를 생각해 보겠습니다.
d = {}
li = [1,2,3]
d[li] = 5
li.append(4)
을 해야 합니까?d[li]
반하?????은은리??리 ???는 요?d[[1,2,3]]
은은값 른른 른른 른른른 른른 른? 른 른?
결국 만족스러운 답변은 없습니다.
동작하는 키가 원래 키뿐일 경우 원래 키에 대한 참조를 유지하지 않으면 값에 액세스할 수 없습니다(또한 해당 키에 대한 액세스 권한이 있음).
같은 내용의 키만 기능하는 경우 키를 변경하면 검색 기능이 변경됩니다.또, 그 리스트에 대한 참조가 있는 그 외의 코드는, 나중에 변경을 가할 가능성이 있습니다.
둘 다 작동하면 매우 다른 키가 동일한 값에 매핑됩니다. 이는 전혀 놀라운 일이 아닙니다.
다음은 답변입니다.http://wiki.python.org/moin/DictionaryKeys
예를 들어 해시를 메모리의 위치로 하여 목록을 키로 사용하려고 하면 어떤 문제가 발생합니까?
동일한 내용을 가진 다른 목록을 검색하면 동일한 내용을 가진 목록을 비교할 경우 동일한 내용을 가진 목록이 동일한 것으로 나타나더라도 다른 결과가 생성됩니다.
사전 검색에서 목록 리터럴을 사용하면 어떨까요?
에, 「」는 「」입니다.dict
")set
members)는 해시 가능해야 하며 해시 값은 인스턴스 속성에 따라 계산해야 하기 때문에 해시 가능한 오브젝트는 좋지 않습니다.
이 답변에서는 기존의 답변 위에 가치를 더하기를 바라며 구체적인 예를 몇 가지 제시하겠습니다.은 그 된다.set
이치노
예 1: 해시 값이 객체의 가변 특성을 기반으로 하는 가변 객체의 해시.
>>> class stupidlist(list):
... def __hash__(self):
... return len(self)
...
>>> stupid = stupidlist([1, 2, 3])
>>> d = {stupid: 0}
>>> stupid.append(4)
>>> stupid
[1, 2, 3, 4]
>>> d
{[1, 2, 3, 4]: 0}
>>> stupid in d
False
>>> stupid in d.keys()
False
>>> stupid in list(d.keys())
True
" " " "stupid
해시가 변경되었기 때문에 더 이상 dict에서 찾을 수 없습니다.키 만 dict를 찾습니다.stupid
.
예 2: ...그런데 왜 그냥 상수 해시 값을 사용하지 않는 거죠?
>>> class stupidlist2(list):
... def __hash__(self):
... return id(self)
...
>>> stupidA = stupidlist2([1, 2, 3])
>>> stupidB = stupidlist2([1, 2, 3])
>>>
>>> stupidA == stupidB
True
>>> stupidA in {stupidB: 0}
False
요. 사물은 수 요. 왜냐하면 동등한 오브젝트는 동일한 해시되어야 하기 때문에dict
★★★★★★★★★★★★★★★★★」set
.
예 3: ...좋아요, 모든 인스턴스에서 지속적인 해시는 어떨까요?
>>> class stupidlist3(list):
... def __hash__(self):
... return 1
...
>>> stupidC = stupidlist3([1, 2, 3])
>>> stupidD = stupidlist3([1, 2, 3])
>>> stupidE = stupidlist3([1, 2, 3, 4])
>>>
>>> stupidC in {stupidD: 0}
True
>>> stupidC in {stupidE: 0}
False
>>> d = {stupidC: 0}
>>> stupidC.append(5)
>>> stupidC in d
True
것이 무슨 이 일어나고 생각해 인스턴스가 값을 하면, 「」의 「키」로서의 인스턴스가 는, 항상 합니다.클래스의 모든 인스턴스가 같은 해시 값을 생성하면, 1개의 키에 2개 이상의 인스턴스가 있을 때마다 해시 충돌이 발생합니다.dict
로 되어 있습니다.set
.
를 사용한 my_dict[key]
★★★★★★★★★★★★★★★★★」key in my_dict
(오류)item in my_set
은(는).stupidlist3
받아쓰다이 시점에서 사전의 목적인 O(1) 룩업은 완전히 무효가 됩니다.이것은, 다음의 타이밍(IPython 를 사용해 실행)으로 확인할 수 있습니다.
예 3의 일부 타이밍
>>> lists_list = [[i] for i in range(1000)]
>>> stupidlists_set = {stupidlist3([i]) for i in range(1000)}
>>> tuples_set = {(i,) for i in range(1000)}
>>> l = [999]
>>> s = stupidlist3([999])
>>> t = (999,)
>>>
>>> %timeit l in lists_list
25.5 µs ± 442 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
>>> %timeit s in stupidlists_set
38.5 µs ± 61.2 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
>>> %timeit t in tuples_set
77.6 ns ± 1.5 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
As you can see, the membership test in our 보시다시피 저희 멤버십테스트는stupidlists_set
is even slower than a linear scan over the whole 전체 선형 스캔보다 속도가 느립니다.lists_list
, 돌 충 되 고 coll 500))isions super of포시팩세검 while 500해은터가없부하있시에트 have fast함 without lookup 는 a loads(다색속단간
TL; DR: you can use TL; DR: 사용할 수 있습니다.tuple(yourlist)
as ~하듯이dict
열쇠, 그것은 단순히 불가능하고 해시를 할 수 있기 때문입니다.키를 지정합니다.왜냐하면 튜플은 불변하고 해시가 가능하기 때문입니다.
질문에 대한 간단한 답변은 클래스 목록이 사전에서 키로 사용하려는 개체에 필요한 메서드 해시를 구현하지 않는 것입니다.단, (컨테이너의 내용에 따라) 태플클래스와 같은 방법으로 해시가 구현되지 않는 이유는 리스트가 변경 가능하기 때문에 목록을 편집하려면 해시를 다시 계산해야 하기 때문입니다.이 경우 언더링 해시 테이블 내의 잘못된 버킷에 리스트가 배치되어 있을 수 있습니다.태플(불변)은 수정할 수 없으므로 이 문제는 발생하지 않습니다.
참고로 딕트 오브젝트 룩업의 실제 구현은 Knuth Vol. 3, 6.4절의 알고리즘 D에 기초하고 있다.이 책이 있다면 읽을 가치가 있을 것입니다.또, 정말로 정말로 관심이 있는 분은, 여기서 dictobject의 실제 실장에 관한 개발자의 코멘트를 봐 주세요.그것이 정확히 어떻게 작동하는지에 대해서는 매우 상세하게 설명된다.여러분이 관심을 가질 만한 사전 구현에 대한 파이썬 강의도 있습니다.이들은 처음 몇 분 동안 키의 정의와 해시가 무엇인지 확인합니다.
awnser는 다음 URL에서 찾을 수 있습니다.
목록이 사전 키가 될 수 없는 이유
Python을 처음 접하는 사람들은 왜 그런지 궁금해 하는 경우가 많은데, 언어에는 태플과 리스트 타입이 모두 포함되어 있지만, 튜플은 사전 키로 사용할 수 있지만 리스트는 사용할 수 없습니다.이것은 의도적인 설계 결정이었고, Python 사전의 작동 방식을 먼저 이해하는 것이 가장 잘 설명될 수 있습니다.
출처 및 상세정보 : http://wiki.python.org/moin/DictionaryKeys
사전은 키 맵, 해시된 새 키로 변환된 값 및 값 매핑을 저장하는 해시 맵입니다.
(psuedo 코드):
{key : val}
hash(key) = val
사전의 키로 사용할 수 있는 옵션이 궁금할 경우.그리고나서
해시 가능한 모든 것(해시로 변환할 수 있고 정적 값을 유지하여 위에서 설명한 해시 키를 만들 수 있음)이 해당되지만 목록 또는 세트 오브젝트가 이동 중에 변경될 수 있으므로 해시(키)도 목록 또는 세트와 동기화되기 위해서만 변화해야 합니다.
다음 작업을 수행할 수 있습니다.
hash(<your key here>)
정상적으로 동작하는 경우는, 사전의 키로 사용하거나, 해시 가능한 것으로 변환할 수 있습니다.
인스호트:
- 를 해해 to to to to to convert convert convert로 변환해 주세요.
tuple(<your list>)
. - 를 해해 to to to to to convert convert convert로 변환해 주세요.
str(<your list>)
.
, 「 」 「 」 「 」 「 」는 주의할 수 .dict
키는 불변(정확하게는 해시 가능)이어야 합니다.리스트는 변경할 수 있습니다(정확히 말하면 리스트는 유효하지 않습니다).__hash__
★★★★★★★★★★★★★★★★★★」
여기서 불변 객체(불변 객체)는 생성된 후 상태를 수정할 수 없는 객체입니다.이는 생성된 후 수정할 수 있는 가변 개체(변경 가능한 개체)와는 대조적입니다.
Python 2.7.2 설명서에 따르면:
그, 합니다(이 는, 「해시 가능」이 에는 「해시 가능」
__hash__()
및 할 수 (메서드가 합니다).__eq__()
★★★★★★★★★★★★★★★★★」__cmp__()
을 비교하는 해시 값을 합니다.동일한 해시 가능 개체는 동일한 해시 값을 가져야 합니다.이러한 데이터 구조에서는 내부적으로 해시 값을 사용하기 때문에 해시 가능성은 개체를 사전 키 및 세트 멤버로 사용할 수 있게 합니다.
Python의 모든 불변 빌트인 객체는 해시 가능하지만 목록이나 사전과 같은 가변 컨테이너는 해시 가능하지 않습니다.인 오브젝트는 해시 오브젝트는 하지 않습니다은 그 입니다.이러한 오브젝트는 모두 동등하지 않으며 해시 값은
id()
.
태플은 요소를 추가, 삭제 또는 교체할 수 없다는 점에서 불변하지만 요소 자체는 변경할 수 있습니다.목록의 해시 값은 요소의 해시 값에 따라 달라지므로 요소를 변경하면 변경됩니다.
목록 해시에 ID를 사용하면 모든 목록이 서로 다르게 비교된다는 것을 의미하므로 놀랍고 불편합니다.
언급URL : https://stackoverflow.com/questions/7257588/why-cant-i-use-a-list-as-a-dict-key-in-python-exactly-what-can-and-cannot-be-u
'programing' 카테고리의 다른 글
Python에서 파일을 이동하려면 어떻게 해야 하나요? (0) | 2023.04.19 |
---|---|
단일 파일 하드 리셋 (0) | 2023.04.13 |
클래스가 NSObjectProtocol을 준수하지 않습니다. (0) | 2023.04.13 |
sed를 사용하여 파일의 마지막 n 행을 삭제하는 방법 (0) | 2023.04.13 |
Bash 스크립트 - 실행할 명령어로서의 가변 콘텐츠 (0) | 2023.04.13 |