파이썬에서 int ()의 직관적이지 않은 동작


83

int (number)가 바닥 유형 변환이라는 것이 문서에 명확하게 명시되어 있습니다.

int(1.23)
1

int (string)은 문자열이 정수 리터럴 인 경우에만 int를 반환합니다.

int('1.23')
ValueError

int('1')
1

특별한 이유가 있습니까? 기능이 한 경우에는 바닥이지만 다른 경우에는 그렇지 않다는 것이 직관적이지 않습니다.

답변:


123

특별한 이유 가 없습니다 . 파이썬은 단순히 묵시적 변환을 수행하지 않는다는 일반적인 원칙을 적용하고 있으며, 이는 특히 Perl 및 Javascript와 같은 언어에서 특히 초보자에게 잘 알려진 문제의 원인입니다.

int(some_string)문자열을 정수 형식으로 변환하기위한 명시 적 요청입니다. 이 변환에 대한 규칙은 문자열이 유효한 정수 리터럴 표현을 포함해야 함을 지정합니다. int(float)부동 소수점을 정수로 변환하기위한 명시 적 요청입니다. 이 변환에 대한 규칙은 float의 소수 부분이 잘 리도록 지정합니다.

위해서는 int("3.1459")반환하는 3암시 적으로 float로 문자열을 변환해야 인터프리터. Python은 암시 적 변환을 지원하지 않으므로 대신 예외를 발생시킵니다.


type(3)를 반환합니다 <type int>. 그러나 파이썬은 float("3"). 파이썬이 암시 적으로 문자열을 int로 변환 한 다음 float로 변환하지 않습니까?
franksands

아니오. "3"은 프로그램 리터럴로서 정수로 해석 되더라도 유효한 부동 소수점 값입니다. 정수 변환이 필요하지 않습니다.
holdenweb

75

이것은 거의 확실하게 Zen of Python 의 세 가지 원칙을 적용한 경우입니다 .

명시 적 일수록 암시 적입니다.

[...] 실용성은 순수함을 이긴다

오류는 조용히 전달되지 않아야합니다.

시간의 일부 비율은, 사람의 행함은 int('1.23')자신의 사용 사례에 대한 잘못된 변환을 호출하고, 같은 싶어한다 floatdecimal.Decimal대신합니다. 이러한 경우에는 잘못된 값을 조용히 제공하는 것보다 수정할 수있는 즉각적인 오류를 얻는 것이 분명 낫습니다.

당신이하는 경우 않는 int로, 명시 적으로 그것을 통해 전달하여 그렇게 사소한 것을 잘라 내기하려는 float첫 번째, 다음 중 하나를 호출 int, round, trunc, floor또는 ceil적절합니다. 이것은 또한 당신의 코드 당신이 원하는 값임을 명확하게함으로써 가설적인 조용히 잘리는 int호출을 "수정"하는 추후 수정으로부터 보호하면서 당신의 코드를 더 자기 문서화하게 만듭니다 .float


저는 이러한 원칙이 선이 공식화되기 훨씬 전에 채택되었다고 생각하지만, 어느 쪽이든 두 가지가 조화를 이루는 것처럼 보입니다.
holdenweb

17

때때로 사고 실험이 유용 할 수 있습니다.

  • 동작 A : int('1.23')오류와 함께 실패합니다. 이것은 기존의 동작입니다.
  • 동작 B : 오류없이 int('1.23')생성 1됩니다. 이것이 당신이 제안하는 것입니다.

행동 A를 사용하면 행동 B의 효과를 얻는 것이 간단하고 간단합니다 int(float('1.23')). 대신 사용하십시오.

반면에 행동 B에서는 행동 A의 효과를 얻는 것이 훨씬 더 복잡합니다.

def parse_pure_int(s):
    if "." in s:
        raise ValueError("invalid literal for integer with base 10: " + s)
    return int(s)

(그리고 위의 코드를 사용해도 잘못 처리되는 코너 케이스가 없다는 완전한 확신이 없습니다.)

따라서 행동 A는 행동 B보다 표현력이 더 뛰어납니다.

고려해야 할 또 다른 사항 '1.23'은 부동 소수점 값의 문자열 표현입니다. 변환 '1.23'정수로하는 것은 개념적으로 두 개의 변환 (정수로 플로트로 문자열)을 포함하지만, int(1.23)int('1')각은 하나의 변환을 포함한다.


편집하다:

그리고 실제로, 위의 코드가 처리하지 않을 것이라고 코너 케이스가있다 : 1e-2그리고 1E-2모두 너무 부동 소수점 값 있습니다.


명확히하기 위해 : 나는 행동 B에 제안하지 않을 것입니다. 왜냐하면 그것은 당신과 다른 사람들이 말했듯이 위험하기 때문입니다. 나는 현재 존재하는 것보다 더 나은 해결책이 있는지 잘 모르겠습니다. 한 가지 옵션은 함수에 다른 이름을 지정하는 것이지만 입력 할 내용이 더 많습니다. int (1.23)가 실패하고 정수를 반환하는 int (float-with-no-decimal-places) 만 동적 형식 언어에서는 의미가 없습니다.
StefanS

1
코너 케이스는 int('123E-2')또는 일 수 있습니다 int('1L').
자레드 Goguen

11

간단히 말해서, 그것들은 동일한 기능이 아닙니다.

  • int (decimal)은 'floor ie 소수점 부분을 제거하고 int로 반환'으로 동작합니다.
  • int (string)은 '이 텍스트는 정수를 설명하고, 변환하고 int로 반환'하는 것처럼 동작합니다.

정수를 반환하는 동일한 이름 을 가진 두 개의 다른 함수 이지만 다른 함수입니다.

'int'는 짧고 기억하기 쉬우 며 각 유형에 적용되는 의미는 대부분의 프로그래머에게 직관적이기 때문에 선택했습니다.

동일하거나 결합 된 기능을 제공한다는 의미는 없으며 단순히 이름이 같고 동일한 유형을 반환합니다. 'floorDecimalAsInt'및 'convertStringToInt'라고 쉽게 불릴 수 있지만 기억하기 쉽고 (99 %) 직관적이고 혼란이 거의 발생하지 않기 때문에 'int'를 사용했습니다.

"4.5"와 같은 소수점을 포함하는 텍스트에 대해 텍스트를 정수로 구문 분석하면 대부분 의 컴퓨터 언어에서 오류가 발생하고 대부분 의 프로그래머 가 오류를 발생시킬 것으로 예상됩니다. 이는 텍스트 값이 정수를 나타내지 않고이를 의미하기 때문입니다. 그들은 잘못된 데이터를 제공하고 있습니다


2
그렇다면 두 개의 '다른 기능'이 같은 이름을 갖는 이유는 무엇입니까? 넌센스를 위반하는 것처럼 들린다.
hobbs

이름이 두 가지 다른 기능에 의미가 있고 간결하기 때문입니다. 소수 (바닥)를

기술적 int으로는 유형 (그리고 내장 유형) 을 기억하는 것이 도움이 될 수 있습니다 . 작성자 ( __new__)는 가능한 여러 인수 유형을 사용합니다. 각 유형에 대한 동작은 잘 정의되어 있습니다.
holdenweb

이 대답은 명시된대로 잘못되었습니다. int사실은 함수가 아니라 유형이며, 그 __new____init__메소드는 각각을 적절하게 처리하는 문자열 또는 부동 인수를 취합니다. 유형이 두 가지 인수 유형을 다르게 처리한다고 말하는 것이 더 정확할 수 있지만 int.
holdenweb
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.