사전에서 비교할 때 키를 선택하기 위해 Python 3.5가 선택한 사항
다음과 같이 사전을 구성 할 때 :
dict = { True: 'yes', 1: 'No'}
대화 형 Python 인터프리터에서 실행하면 dict가 다음과 같이 표시됩니다.
dict = {True: 'No'}
I의 값을 이해 True
하고 1
숫자 형식을 비교하면, 좁은 타입 (부울 정수의 자식) 다른 유형으로 확대되기 때문에, 강압 형 때문에 동일하다. 그래서 나는 우리가 입력 한 문서에서 이해되는 True == 1
파이썬 변환 True
에를 1
와 비교합니다.
내가 이해하지 못하는 것은 True
이 대신 키로 선택된 이유 입니다 1
.
내가 뭔가를 놓치고 있습니까?
사전은 해시 테이블로 구현되며 여기에 키 / 값을 추가 할 때 두 가지 중요한 개념 인 해싱 및 같음이 있습니다.
특정 키 / 값을 삽입하기 위해 Python은 먼저 키 의 해시 값을 계산합니다 . 이 해시 값은 Python이 먼저 키 / 값을 입력해야하는 테이블의 행을 결정하는 데 사용됩니다.
해시 테이블의 행이 비어 있으면 좋습니다. 새 키 / 값을 사전에 삽입하여 빈 행을 채울 수 있습니다.
그러나 해당 행에 이미 무언가가있는 경우 Python은 키가 같은지 테스트해야합니다. 키가 같으면 (사용 ==
) 동일한 키로 간주되며 Python은 해당 행의 해당 값을 업데이트하면됩니다.
(키가 같지 않은 경우 Python은 키를 찾거나 빈 행에 도달 할 때까지 테이블의 다른 행을 살펴 보지만이 질문과는 관련이 없습니다.)
를 작성할 때 {True: 'yes', 1: 'No'}
Python에 새 사전을 만든 다음 두 개의 키 / 값 쌍으로 채우도록 지시하는 것입니다. 왼쪽에서 오른쪽으로 처리됩니다. True: 'yes'
그런 다음 1: 'No'
.
우리는 hash(True)
1 과 같습니다. 키 True
는 해시 테이블의 행 1에 들어가고 문자열 'yes'
은 그 값입니다.
다음 쌍의 경우 Python은이 hash(1)
값도 1 인 것을보고 테이블의 1 행을 봅니다. 이미 거기에 무언가가 있으므로 이제 Python은 키가 같은지 확인합니다. 우리는 한 1 == True
지금 1
과 같은 열쇠가 될 것으로 간주됩니다 True
에 대응하는 값이 문자열로 변경되고 정도 'No'
.
결과적으로 하나의 항목이있는 사전이 생성됩니다 {True: 'No'}
..
CPython 3.5의 내장을 들여다보고 사전을 만드는 것이 표면 Python 수준 아래에서 어떻게 보이는지 확인하려면 여기에 더 자세한 내용이 있습니다.
Python 코드
{True: 'yes', 1: 'No'}
는 토큰으로 구문 분석되어 컴파일러에 제공됩니다. 구문이 주어지면 Python은 중괄호 안의 값을 사용하여 사전을 만들어야한다는 것을 알고 있습니다. 4 개의 값을 가상 머신의 스택 (LOAD_CONST
) 에로드 한 다음 사전 (BUILD_MAP
) 을 빌드하는 바이트 코드 가 대기열에 추가됩니다.4 개의 상수 값이 보이는 순서대로 스택의 맨 위에 푸시됩니다.
'No' 1 'yes' True
BUILD_MAP
그런 다음 opcode 가 인수와 함께 호출됩니다2
(Python은 두 개의 키 / 값 쌍을 계산 함). 이 opcode는 실제로 스택의 항목에서 사전을 생성합니다. 그것은 모양 이 :
TARGET(BUILD_MAP) { int i; PyObject *map = _PyDict_NewPresized((Py_ssize_t)oparg); if (map == NULL) goto error; for (i = oparg; i > 0; i--) { int err; PyObject *key = PEEK(2*i); PyObject *value = PEEK(2*i - 1); err = PyDict_SetItem(map, key, value); if (err != 0) { Py_DECREF(map); goto error; } } while (oparg--) { Py_DECREF(POP()); Py_DECREF(POP()); } PUSH(map); DISPATCH(); }
여기에서 세 가지 주요 단계는 다음과 같습니다.
빈 해시 테이블은
_PyDict_NewPresized
. 작은 사전 (이 경우 2 개와 같은 몇 개의 항목)에는 8 개의 행이있는 테이블이 필요합니다.for
루프 (이 경우) (2)에서 시작하여 0으로 카운트 다운, 입력하는PEEK(n)
매크로 있다는 스택 아래 n 번째 항목 포인트. 따라서 루프의 첫 번째 반복에서
PyObject *key = PEEK(2*2); /* item 4 down the stack */
PyObject *value = PEEK(2*2 - 1); /* item 3 down the stack */
이 수단 *key
것 True
및 *value
것이다 'yes'
내지 제 루프. 두 번째에는 1
및 'No'
.
PyDict_SetItem
현재를 넣어 각 루프에서 호출*key
하고*value
사전에. 이것은 당신이 쓸 때 호출되는 동일한 함수입니다dictionary[key] = value
. 키의 해시를 계산하여 해시 테이블에서 먼저 찾을 위치를 파악한 다음 필요한 경우 키를 해당 행의 기존 키와 비교합니다 (위에서 설명한대로).
기본 전제는 - True
와 1
같은 해시가 서로 동일 - (- 해시 충돌 성능이 저하 할 수 있지만 같은 해시 기술적으로 inequal 객체)가 해시 테이블에 별도의 키가 될 수없는 이유가 있습니다.
>>> True == 1
True
>>> hash(1)
1
>>> hash(True)
1
이제 바이트 코드를 살펴 보겠습니다.
import dis
dis.dis("Dic = { True: 'yes', 1: 'No'}")
이것은 다음을 인쇄합니다.
0 LOAD_CONST 0 (True)
3 LOAD_CONST 1 ('yes')
6 LOAD_CONST 2 (1)
9 LOAD_CONST 3 ('No')
12 BUILD_MAP 2
15 STORE_NAME 0 (Dic)
18 LOAD_CONST 4 (None)
21 RETURN_VALUE
기본적으로 dict 리터럴이 키와 값으로 토큰 화되고 스택으로 푸시됩니다. 그 후 BUILD_MAP 2
두 쌍의 (키, 값)을 사전으로 변환합니다.
Most likely order of data on stack (which seems to be determined by order of keys in dict literal) and implementation details of BUILD_MAP
decides on resulting dict keys and values.
It seems like key-value assignments are done in order defined in dict literal. Assignment behaves same as d[key] = value
operation, so it's basically:
- if
key
is not in dict (by equality): addkey
do dict - store
value
underkey
Given {True: 'yes', 1: 'No'}
:
- Start with
{}
Add
(True, 'yes')
- True is not in dict ->
(True, hash(True))
==(True, 1)
is new key in dict - Update value for key equal to
1
to'yes'
- True is not in dict ->
Add
(1, 'no')
1
is in dict (1 == True
) -> there is no need for new key in dictionary- Update value for key equal to
1
(True
) with value'no'
Result: {True: 'No'}
As I commented, I do not know if this is guarranted by Python specs or if it is just CPython implementation-defined behavior, it may differ in other interpreter implementations.
True
and 1
are different objects, but they both have the same value:
>>> True is 1
False
>>> True == 1
True
This is similar to two strings that may have the same value, but are stored in different memory locations:
>>> x = str(12345)
>>> y = str(12345)
>>> x == y
True
>>> x is y
False
First one item is added to the dictionary; then when the other is added, that value already exists as a key. So the key is updated, key values are unique.
>>> {x: 1, y: 2}
{"12345": 2}
If the key is already present in the dictionary, it does not override the key only the value associated.
I believe that writing x = {True:"a", 1:"b"}
is along the lines of:
x = {}
x[True] = "a"
x[1] = "b"
and by the time it reaches x[1] = "b"
the key True
is already in the dict so why change it? why not just override the associated value.
The ordering seems to be the reason. Code example:
>>> d = {True: 'true', 1: 'one'}
>>> d
{True: 'one'}
>>> d = {1: 'one', True: 'true'}
>>> d
{1: 'true'}
It's an ambiguous statement.
Logic: d = { True: 'no', 1: 'yes'}
When python evaluates the expression, it does it sequentially, so it's equivalent to this.
d = dict() d[True] = 'no' d[1] = 'yes'
The constant True is the key, but it evaluates to 1, so you're just setting the value for the key twice.
'Program Tip' 카테고리의 다른 글
`sizeof`가 * 정말 *`std :: size_t`로 평가됩니까? (0) | 2020.12.04 |
---|---|
생성자에 NULL 전송 (0) | 2020.12.04 |
명령 패턴 : 명령에 매개 변수를 전달하는 방법은 무엇입니까? (0) | 2020.12.04 |
정수를 십진수로 풀 수없는 이유는 무엇입니까? (0) | 2020.12.04 |
문자열이 try-catch없이 Long으로 구문 분석 가능한지 확인하십시오. (0) | 2020.12.04 |