if x is 0이 어떤 환경에서는 되고 어떤 환경에서는 안 됐던 이유
문제 발생
로컬에서 통과하던 조건이 다른 환경에서 거짓이 됐습니다.
x = 7
y = 7
x is y # True
x = 123456789
y = 123456789
x is y # False원인 분석
두 연산자는 다른 것을 묻습니다.
==— 값이 같은가is— 같은 객체인가 (파이썬 문서의 표현으로,x is y는 x와 y가 동일한 객체일 때에만 참입니다)
CPython은 자주 쓰이는 작은 정수를 미리 만들어 캐시합니다. 그래서 7은 어디서 만들어도 같은 객체이고 is가 참이 됩니다. 123456789는 캐시 대상이 아니라 각각 새 객체이므로 거짓입니다.
중요한 건 이게 언어의 약속이 아니라는 점입니다. 파이썬 문서는 이 동작이 향후 CPython 버전에서 바뀔 수 있고, "작은 정수"와 "큰 정수"의 경계는 이미 과거에 바뀐 적이 있다고 명시합니다. 문자열의 인터닝도 마찬가지로 구현에 달려 있습니다.
즉 is로 값을 비교하면 우연히 동작하는 코드가 됩니다.
해결 방안
- 값 비교에는
==를 씁니다.
if count == 0:
...is는 싱글턴에만 씁니다. PEP 8의 권고입니다 — 싱글턴 비교는 항상is/is not으로 하고 등호 연산자를 쓰지 않습니다.
if value is None: ...
if flag is True: ... # 굳이 필요하면
if result is NotImplemented: ...is None을== None으로 쓰지 않습니다.__eq__를 정의한 객체는== None에서 예상과 다른 결과를 낼 수 있습니다(numpy 배열이 대표적입니다).None은 싱글턴이므로is가 정확하고 빠릅니다.- 리터럴 비교에
is를 쓰면 경고가 납니다. CPython이SyntaxWarning을 내므로 경고를 무시하지 않으면 배포 전에 걸립니다. - "같은 객체인지"가 정말 궁금할 때만
is를 씁니다. 캐시 적중 여부나 얕은 복사 확인 같은 경우입니다.
copied = original[:]
copied == original # True — 값이 같다
copied is original # False — 다른 객체다
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.