Nice programing

부동 소수점 사전 키가 같은 값을 가진 정수 키를 덮어 쓸 수있는 이유는 무엇입니까?

nicepro 2021. 1. 5. 21:12
반응형

부동 소수점 사전 키가 같은 값을 가진 정수 키를 덮어 쓸 수있는 이유는 무엇입니까?


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데이터를 표현하는 방법이 아니라 논리 숫자 값에 따라 데이터를 저장 하는 것이 목적 이라는 것을 고려해야 합니다.

ints와 floats 의 차이점 은 실제로 개념이 아닌 구현 세부 사항입니다. 이상적으로 유일한 숫자 유형은 무한한 정확도를 가진 임의의 정밀도 숫자 여야합니다 ... 이것은 문제없이 구현하기 어렵습니다 ...하지만 이것이 파이썬을위한 유일한 미래 숫자 유형일 수 있습니다.

따라서 기술적 인 이유로 다른 유형을 가지고 있지만 Python은 이러한 구현 세부 정보를 숨기려고 시도하고 int-> float변환은 자동입니다.

파이썬 프로그램의 경우는 훨씬 더 놀라운 일이 될 if x == 1: ...때 수행하지 않을 된 xA는 float값 1.

또한 Python 3에서의 값 1/20.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.01동일한 방식으로 정확하게 작동 dict키 따라서 동작한다.

즉, 동작 자체가 어떤 식 으로든 사용되거나 유용 할 필요가 없습니다. 필요 합니다. 이러한 동작이 없으면 실수로 다른 키를 덮어 쓸 수있는 경우가 있습니다.

우리가 있던 경우에 1.0 == 1그러나 hash(1.0) != hash(1)우리는 여전히있을 수 충돌 . 그리고 만약 1.01에서 충돌의는 dict그들이 동일한 키 또는하지 있는지 여부로 평등을 사용 터져 죽자 값이 서로 다른 수를위한 경우에도 덮어 쓰기 가져옵니다.

이것을 피하는 유일한 방법은를 갖는 것입니다 1.0 != 1. 그래야 dict충돌이 발생한 경우에도에서 구분할 수 있습니다. 그러나 1.0 == 1실제로 floats와 ints를 사전 키로 사용하지 않기 때문에 현재보고있는 동작을 피하는 것보다 갖는 것이 더 중요하다고 간주 되었습니다.

파이썬은 필요할 때 자동으로 숫자를 변환하여 (예 :) 숫자 사이의 구분을 숨기려고하기 때문에 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

내가 간 이유를 자동 캐스팅을 볼 수 있습니다 floatint편리, 그것은 캐스트 상대적으로 안전 intfloat아직 다른 언어 (예 : 이동) 떨어진 암시 적 캐스팅에서 해당 숙박이있다.

실제로 언어 디자인 결정이며 다른 기능보다 취향의 문제입니다.


사전은 해시 테이블로 구현됩니다. 해시 테이블에서 무언가를 찾으려면 해시 값으로 표시된 위치에서 시작한 다음 동일하거나 빈 버킷 인 키 값을 찾을 때까지 다른 위치를 검색합니다.

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 including set, frozenset, and dict. __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

반응형