부동 소수점 사전 키가 같은 값을 가진 정수 키를 덮어 쓸 수있는 이유는 무엇입니까?
http://www.mypythonquiz.com을 통해 작업 하고 있으며 질문 # 45 는 다음 코드의 출력을 요청합니다.
confusion = {}
confusion[1] = 1
confusion['1'] = 2
confusion[1.0] = 4
sum = 0
for k in confusion:
sum += confusion[k]
print sum
출력은 6
키 때문에 1.0
대체합니다 1
. 이것은 나에게 약간 위험하다고 느낍니다. 이것은 유용한 언어 기능입니까?
dict
데이터를 표현하는 방법이 아니라 논리 숫자 값에 따라 데이터를 저장 하는 것이 목적 이라는 것을 고려해야 합니다.
int
s와 float
s 의 차이점 은 실제로 개념이 아닌 구현 세부 사항입니다. 이상적으로 유일한 숫자 유형은 무한한 정확도를 가진 임의의 정밀도 숫자 여야합니다 ... 이것은 문제없이 구현하기 어렵습니다 ...하지만 이것이 파이썬을위한 유일한 미래 숫자 유형일 수 있습니다.
따라서 기술적 인 이유로 다른 유형을 가지고 있지만 Python은 이러한 구현 세부 정보를 숨기려고 시도하고 int
-> float
변환은 자동입니다.
파이썬 프로그램의 경우는 훨씬 더 놀라운 일이 될 if x == 1: ...
때 수행하지 않을 된 x
A는 float
값 1.
또한 Python 3에서의 값 1/2
은 0.5
(두 정수의 나눗셈)이며, long
구현 세부 정보를 숨기려는 동일한 시도로 유형 및 비 유니 코드 문자열이 삭제되었습니다.
우선, 동작은 해시 함수에 대한 문서에 명시 적으로 문서화되어 있습니다.
hash(object)
객체의 해시 값을 반환합니다 (있는 경우). 해시 값은 정수입니다. 사전 조회 중에 사전 키를 빠르게 비교하는 데 사용됩니다. 동일하게 비교되는 숫자 값은 동일한 해시 값을 갖습니다 (
1
및 의 경우 와 같이 유형이 다르더라도1.0
).
둘째, 해싱의 제한은 문서에서 object.__hash__
object.__hash__(self)
에 의해 호출 기능 내장
hash()
을 포함한 해시 컬렉션의 구성원과 작업set
,frozenset
그리고dict. __hash__()
정수를 반환해야합니다. 유일한 필수 속성은 동일하게 비교되는 객체가 동일한 해시 값을 갖는 것입니다.
이것은 파이썬에만 국한되지 않습니다. 자바는 같은주의를 가지고 : 당신이 구현하는 경우 hashCode
상황이 당신이 제대로 작동하기 위해서는, 다음 있어야 하는 방식이 그것을 구현 : x.equals(y)
의미한다 x.hashCode() == y.hashCode()
.
그래서, 파이썬은 그 결정 1.0 == 1
따라서있어, 보유하고 강제 에 대한 구현을 제공하는 hash
등 그 hash(1.0) == hash(1)
. 부작용이 있다는 것이다 1.0
와 1
동일한 방식으로 정확하게 작동 dict
키 따라서 동작한다.
즉, 동작 자체가 어떤 식 으로든 사용되거나 유용 할 필요가 없습니다. 필요 합니다. 이러한 동작이 없으면 실수로 다른 키를 덮어 쓸 수있는 경우가 있습니다.
우리가 있던 경우에 1.0 == 1
그러나 hash(1.0) != hash(1)
우리는 여전히있을 수 충돌 . 그리고 만약 1.0
과 1
에서 충돌의는 dict
그들이 동일한 키 또는하지 있는지 여부로 평등을 사용 터져 죽자 값이 서로 다른 수를위한 경우에도 덮어 쓰기 가져옵니다.
이것을 피하는 유일한 방법은를 갖는 것입니다 1.0 != 1
. 그래야 dict
충돌이 발생한 경우에도에서 구분할 수 있습니다. 그러나 1.0 == 1
실제로 float
s와 int
s를 사전 키로 사용하지 않기 때문에 현재보고있는 동작을 피하는 것보다 갖는 것이 더 중요하다고 간주 되었습니다.
파이썬은 필요할 때 자동으로 숫자를 변환하여 (예 :) 숫자 사이의 구분을 숨기려고하기 때문에 1/2 -> 0.5
이러한 상황에서도이 동작이 반영된다는 것이 합리적입니다. 나머지 파이썬과 더 일치합니다.
이 동작은 키의 일치가 비교를 기반으로 적어도 부분적으로 (해시 맵에서와 같이) 되는 모든 구현에서 나타납니다 .
예를 들어 a dict
가 빨강-검정 트리 또는 다른 종류의 균형 BST를 사용하여 구현 된 경우 키 1.0
를 조회 할 때 다른 키와의 비교는 for 1
와 동일한 결과를 반환 하므로 동일한 방식으로 작동합니다.
해시 맵은 키의 항목을 찾는 데 사용되는 해시 값이고 그 후에 만 비교가 수행되기 때문에 더 많은주의가 필요합니다. 따라서 위에 제시된 규칙을 위반하면 버그가 dict
예상대로 작동하는 것처럼 보일 수 있고, 크기가 변경되면 잘못 작동하기 시작하기 때문에 발견하기 매우 어려운 버그가 도입 됩니다.
이 것을 참고 것이 이 문제를 해결하는 방법이 될 수는 : 사전에 삽입 된 각 유형에 대해 별도의 해시 맵 / BST 있습니다. 이런 식으로 다른 유형의 객체간에 충돌 ==
이 발생하지 않으며 인수가 다른 유형을 가질 때 비교가 어떻게 중요하지 않을 수 있습니다.
그러나 이것은 구현을 복잡하게 만들 수 있으며, O (1) 액세스 시간을 갖기 위해 해시 맵이 많은 자유 위치를 유지해야하므로 비효율적 일 것입니다. 너무 꽉 차면 공연이 감소합니다. 여러 해시 맵이 있다는 것은 더 많은 공간을 낭비한다는 것을 의미하며 키의 실제 조회를 시작하기 전에 먼저 살펴볼 해시 맵을 선택해야합니다.
BST를 사용한 경우 먼저 유형을 조회하고 두 번째 조회를 수행해야합니다. 따라서 많은 유형을 사용하려는 경우 두 배의 작업으로 끝날 것입니다 (검색은 O (1) 대신 O (log n)을 사용합니다).
파이썬에서 :
1==1.0
True
암시 적 캐스팅 때문입니다.
하나:
1 is 1.0
False
내가 간 이유를 자동 캐스팅을 볼 수 있습니다 float
및 int
편리, 그것은 캐스트 상대적으로 안전 int
에 float
아직 다른 언어 (예 : 이동) 떨어진 암시 적 캐스팅에서 해당 숙박이있다.
실제로 언어 디자인 결정이며 다른 기능보다 취향의 문제입니다.
사전은 해시 테이블로 구현됩니다. 해시 테이블에서 무언가를 찾으려면 해시 값으로 표시된 위치에서 시작한 다음 동일하거나 빈 버킷 인 키 값을 찾을 때까지 다른 위치를 검색합니다.
If you have two key values that compare equal but have different hashes, you may get inconsistent results depending on whether the other key value was in the searched locations or not. For example this would be more likely as the table gets full. This is something you want to avoid. It appears that the Python developers had this in mind, since the built-in hash
function returns the same hash for equivalent numeric values, no matter if those values are int
or float
. Note that this extends to other numeric types, False
is equal to 0
and True
is equal to 1
. Even fractions.Fraction
and decimal.Decimal
uphold this property.
The requirement that if a == b
then hash(a) == hash(b)
is documented in the definition of object.__hash__()
:
Called by built-in function
hash()
and for operations on members of hashed collections includingset
,frozenset
, anddict
.__hash__()
should return an integer. The only required property is that objects which compare equal have the same hash value; it is advised to somehow mix together (e.g. using exclusive or) the hash values for the components of the object that also play a part in comparison of objects.
TL;DR: a dictionary would break if keys that compared equal did not map to the same value.
Frankly, the opposite is dangerous! 1 == 1.0
, so it's not improbable to imagine that if you had them point to different keys and tried to access them based on an evaluated number then you'd likely run into trouble with it because the ambiguity is hard to figure out.
Dynamic typing means that the value is more important than what the technical type of something is, since the type is malleable (which is a very useful feature) and so distinguishing both ints
and floats
of the same value as distinct is unnecessary semantics that will only lead to confusion.
I agree with others that it makes sense to treat 1
and 1.0
as the same in this context. Even if Python did treat them differently, it would probably be a bad idea to try to use 1
and 1.0
as distinct keys for a dictionary. On the other hand -- I have trouble thinking of a natural use-case for using 1.0
as an alias for 1
in the context of keys. The problem is that either the key is literal or it is computed. If it is a literal key then why not just use 1
rather than 1.0
? If it is a computed key -- round off error could muck things up:
>>> d = {}
>>> d[1] = 5
>>> d[1.0]
5
>>> x = sum(0.01 for i in range(100)) #conceptually this is 1.0
>>> d[x]
Traceback (most recent call last):
File "<pyshell#12>", line 1, in <module>
d[x]
KeyError: 1.0000000000000007
So I would say that, generally speaking, the answer to your question "is this ever a useful language feature?" is "No, probably not."
ReferenceURL : https://stackoverflow.com/questions/32209155/why-can-a-floating-point-dictionary-key-overwrite-an-integer-key-with-the-same-v
'Nice programing' 카테고리의 다른 글
웹 게시 암호가 내 Azure 관리자 암호와 같지 않습니까? (0) | 2021.01.05 |
---|---|
React Native : 요소의 위치 얻기 (0) | 2021.01.05 |
동적 키로 객체의 PropTypes 검사 (0) | 2021.01.05 |
항목의 수평 배열이있는 WPF ListView? (0) | 2021.01.05 |
상대 경로를 절대 경로로 변환 하시겠습니까? (0) | 2021.01.05 |