문제

왜 다음이 Python에서 예기치 않게 행동합니까?

>>> a = 256
>>> b = 256
>>> a is b
True           # This is an expected result
>>> a = 257
>>> b = 257
>>> a is b
False          # What happened here? Why is this False?
>>> 257 is 257
True           # Yet the literal numbers compare properly

Python 2.5.2를 사용하고 있습니다. Python 2.3.3은 몇 가지 다른 버전의 Python을 시도하면 99와 100 사이의 위의 동작을 보여줍니다.

위의 내용을 기반으로, 파이썬이 내부적으로 구현되어 "작은"정수가 더 큰 정수와 다른 방식으로 저장되도록 내부적으로 구현된다는 가설을 세울 수 있습니다. is 운영자는 차이를 알 수 있습니다. 누출 된 추상화는 왜인가? 두 개의 임의의 개체를 비교하여 숫자인지 아닌지 미리 알지 못할 때 동일인지 확인하는 더 좋은 방법은 무엇입니까?

도움이 되었습니까?

해결책

이것을 살펴보십시오 :

>>> a = 256
>>> b = 256
>>> id(a)
9987148
>>> id(b)
9987148
>>> a = 257
>>> b = 257
>>> id(a)
11662816
>>> id(b)
11662828

편집 : Python 2 문서에서 찾은 내용은 다음과 같습니다. "일반 정수 물체" (동일합니다 파이썬 3):

현재 구현은 -5에서 256 사이의 모든 정수에 대한 정수 객체를 유지합니다. 해당 범위에서 int를 생성 할 때 실제로 기존 객체에 대한 참조를 다시 얻습니다. 따라서 1의 값을 변경할 수 있어야합니다.이 경우 파이썬의 동작이 정의되지 않은 것으로 생각됩니다. :-)

다른 팁

Python의 "IS"연산자는 정수와 예기치 않게 행동합니까?

요약 - 강조하겠습니다. 사용하지 마세요 is 정수를 비교합니다.

이것은 당신이 기대하는 행동이 아닙니다.

대신 사용하십시오 == 그리고 != 평등과 불평등을 각각 비교합니다. 예를 들어:

>>> a = 1000
>>> a == 1000       # Test integers like this,
True
>>> a != 5000       # or this!
True
>>> a is 1000       # Don't do this! - Don't use `is` to test integers!!
False

설명

이것을 알기 위해서는 다음을 알아야합니다.

첫째, 무엇을 하는가 is 하다? 비교 연산자입니다. 로부터 선적 서류 비치:

연산자 is 그리고 is not 객체 아이덴티티 테스트 : x is y x와 y가 동일한 객체 인 경우에만 사실입니다. x is not y 역 진실 값을 산출합니다.

그리고 다음은 동일합니다.

>>> a is b
>>> id(a) == id(b)

로부터 선적 서류 비치:

id객체의“정체성”을 반환하십시오. 이것은 정수 (또는 긴 정수)로, 수명 동안이 객체에 대해 독특하고 일정하게 보장됩니다. 겹치지 않는 수명이없는 두 개의 물체는 동일 할 수 있습니다 id() 값.

CPYTHON (Python의 참조 구현)에서 객체의 ID가 메모리의 위치라는 사실은 구현 세부 사항이라는 사실에 유의하십시오. Python의 다른 구현 (예 : Jython 또는 Ironpython)은 쉽게 다른 구현을 가질 수 있습니다. id.

따라서 사용 사례는 무엇입니까? is? PEP8을 설명합니다:

싱글 톤과 비교 None 항상 완료해야합니다 is 또는 is not, 평등 운영자는 절대 없습니다.

질문

다음 질문 (코드 포함)을 묻고 말합니다.

왜 다음이 Python에서 예기치 않게 행동합니까?

>>> a = 256
>>> b = 256
>>> a is b
True           # This is an expected result

그것은이다 ~ 아니다 예상 결과. 왜 예상 되는가? 그것은 단지 정수의 가치가 있음을 의미합니다 256 둘 다 참조 a 그리고 b 정수의 동일한 인스턴스입니다. 정수는 파이썬에서 불변이 없으므로 변경할 수 없습니다. 이것은 모든 코드에 영향을 미치지 않아야합니다. 예상되지 않아야합니다. 단지 구현 세부 사항 일뿐입니다.

그러나 아마도 우리는 값을 256에 동일 할 때마다 메모리에 새로운 별도의 인스턴스가 없다는 것을 기쁘게 생각합니다.

>>> a = 257
>>> b = 257
>>> a is b
False          # What happened here? Why is this False?

이제 우리는 이제 값을 가진 두 개의 별도의 정수 인스턴스를 가지고있는 것 같습니다. 257 메모리에서. 정수는 불변이기 때문에 기억을 낭비합니다. 우리가 그것을 많이 낭비하지 않기를 바랍니다. 우리는 아마 그렇지 않을 것입니다. 그러나이 행동은 보장되지 않습니다.

>>> 257 is 257
True           # Yet the literal numbers compare properly

글쎄, 이것은 당신의 특정 Python 구현이 똑똑하려고 노력하고 있고, 그럴 필요가 없다면 메모리에서 중복 가치있는 정수를 만들지 않는 것처럼 보입니다. CPYTHON 인 Python의 지시 구현을 사용하고 있음을 나타냅니다. cpython에 좋습니다.

CPYTHON이 전 세계적 으로이 작업을 수행 할 수 있다면 더 나을 수 있습니다. 저렴하게 (조회에 비용이 들기 때문에) 또 다른 구현이 가능할 수 있습니다.

그러나 코드에 미치는 영향은 정수가 정수의 특정 인스턴스인지 신경 쓰지 않아야합니다. 해당 인스턴스의 가치 만 신경 쓰야하며 정상 비교 연산자를 사용합니다. ==.

is 하다

is 그것을 확인합니다 id 두 객체 중 동일합니다. Cpython에서 id 메모리의 위치이지만 다른 구현에서 독특하게 식별하는 다른 숫자 일 수 있습니다. 코드로 이것을 다시 사용할 수 있습니다.

>>> a is b

와 같다

>>> id(a) == id(b)

왜 우리가 사용하고 싶은가? is 그 다음에?

이것은 두 개의 매우 긴 문자열이 값이 같는지 확인하는 것과 비교하여 매우 빠른 점검 일 수 있습니다. 그러나 그것이 대상의 독창성에 적용되므로, 우리는 그것에 대한 제한된 사용 사례를 가지고 있습니다. 사실, 우리는 주로 그것을 확인하기 위해 그것을 사용하고 싶습니다. None, 이것은 싱글 톤입니다 (메모리의 한 곳에 존재하는 유일한 인스턴스). 우리는 그것들을 혼동 할 가능성이 있다면 다른 싱글 톤을 만들 수 있습니다. is, 그러나 이것들은 비교적 드 rare니다. 다음은 예입니다 (Python 2 및 3에서 작동합니다)

SENTINEL_SINGLETON = object() # this will only be created one time.

def foo(keyword_argument=None):
    if keyword_argument is None:
        print('no argument given to foo')
    bar()
    bar(keyword_argument)
    bar('baz')

def bar(keyword_argument=SENTINEL_SINGLETON):
    # SENTINEL_SINGLETON tells us if we were not passed anything
    # as None is a legitimate potential argument we could get.
    if keyword_argument is SENTINEL_SINGLETON:
        print('no argument given to bar')
    else:
        print('argument to bar: {0}'.format(keyword_argument))

foo()

어떤 인쇄 :

no argument given to foo
no argument given to bar
argument to bar: None
argument to bar: baz

그래서 우리는 함께 볼 수 있습니다 is 그리고 센티넬, 우리는 bar 논쟁이없고 부름을받을 때 None. 이것들은 기본 사용 사례입니다 is - 하다 ~ 아니다 정수, 줄, 튜플 또는 이와 같은 다른 것들의 평등을 테스트하는 데 사용하십시오.

그것은 두 가지가 같거나 같은 객체인지 확인 하려는지 여부에 따라 다릅니다.

is 그것들이 동일하지 않고 동일한 객체인지 확인합니다. 작은 INT는 아마도 공간 효율성을 위해 동일한 메모리 위치를 가리키고있을 것입니다.

In [29]: a = 3
In [30]: b = 3
In [31]: id(a)
Out[31]: 500729144
In [32]: id(b)
Out[32]: 500729144

당신은 사용해야합니다 == 임의의 대상의 평등을 비교합니다. 당신은 동작을 지정할 수 있습니다 __eq__, 그리고 __ne__ 속성.

늦었지만 답이있는 소스를 원하십니까?*

Cpython의 좋은 점은 실제로 이것의 소스를 볼 수 있다는 것입니다. 나는 링크를 사용할 것입니다 3.5 지금은 출시; 해당 찾기 2.x 하나는 사소합니다.

Cpython에서 C-API 새로운 생성을 처리하는 기능 int 대상은 PyLong_FromLong(long v). 이 기능에 대한 설명은 다음과 같습니다.

현재 구현은 -5에서 256 사이의 모든 정수에 대한 정수 객체를 유지합니다. 해당 범위에서 int를 만들 때 실제로 기존 객체에 대한 참조를 다시 얻습니다.. 따라서 1의 값을 변경할 수 있어야합니다.이 경우 파이썬의 동작이 정의되지 않은 것으로 생각됩니다. :-)

당신에 대해 모르지만 나는 이것을보고 생각합니다. 그 배열을 찾아 봅시다!

당신이 The와 함께하지 않았다면 C CPYTHON 구현 코드 당신은해야합니다, 모든 것은 꽤 조직적이고 읽을 수 있습니다. 우리의 경우, 우리는 Objects/ 하위 디렉토리기본 소스 코드 디렉토리 트리.

PyLong_FromLong 처리합니다 long 우리가 내부를 엿볼 필요가 있다고 추론하기가 어렵지 않아야합니다. longobject.c. 내부를 보면 당신은 사물이 혼란 스럽다고 생각할 수 있습니다. 그들은 우리가 찾고있는 기능이 차가워 지지만 두려워하지 않습니다. line 230 우리가 그것을 확인하기를 기다리고 있습니다. 작은 기능이므로 본체 (선언 제외)가 여기에 쉽게 붙여 넣습니다.

PyObject *
PyLong_FromLong(long ival)
{
    // omitting declarations

    CHECK_SMALL_INT(ival);

    if (ival < 0) {
        /* negate: cant write this as abs_ival = -ival since that
           invokes undefined behaviour when ival is LONG_MIN */
        abs_ival = 0U-(unsigned long)ival;
        sign = -1;
    }
    else {
        abs_ival = (unsigned long)ival;
    }

    /* Fast path for single-digit ints */
    if (!(abs_ival >> PyLong_SHIFT)) {
        v = _PyLong_New(1);
        if (v) {
            Py_SIZE(v) = sign;
            v->ob_digit[0] = Py_SAFE_DOWNCAST(
                abs_ival, unsigned long, digit);
        }
        return (PyObject*)v; 
}

이제 우리는 아닙니다 C 마스터 코드 -haxxorz 그러나 우리는 또한 멍청하지 않습니다. 우리는 그것을 볼 수 있습니다 CHECK_SMALL_INT(ival); 우리를 모두 매혹적으로 엿볼 수 있습니다. 우리는 그것이 이것과 관련이 있다는 것을 이해할 수 있습니다. 확인 해보자:

#define CHECK_SMALL_INT(ival) \
    do if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) { \
        return get_small_int((sdigit)ival); \
    } while(0)

따라서 기능을 호출하는 매크로입니다 get_small_int 값이라면 ival 조건을 만족합니다.

if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS)

그래서 무엇입니까 NSMALLNEGINTS 그리고 NSMALLPOSINTS? 당신이 매크로를 추측했다면 당신은 그렇게 어려운 질문이 아니기 때문에 아무것도 얻지 못합니다 .. 어쨌든, 그들은 여기 있습니다:

#ifndef NSMALLPOSINTS
#define NSMALLPOSINTS           257
#endif
#ifndef NSMALLNEGINTS
#define NSMALLNEGINTS           5
#endif

그래서 우리의 상태입니다 if (-5 <= ival && ival < 257) 전화 get_small_int.

갈 곳은 없지만 보면서 우리의 여행을 계속하십시오. get_small_int 모든 영광에서 (글쎄, 우리는 단지 흥미로운 것이기 때문에 몸을 볼 것입니다) : :

PyObject *v;
assert(-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS);
v = (PyObject *)&small_ints[ival + NSMALLNEGINTS];
Py_INCREF(v);

좋아, 선언 a PyObject, 이전 조건이 과제를 보유하고 실행한다고 주장합니다.

v = (PyObject *)&small_ints[ival + NSMALLNEGINTS];

small_ints 우리가 찾고 있던 배열처럼 보입니다. 그리고 그것은! 우리는 방금 망할 문서를 읽을 수 있었고 우리는 모두 알고 있었을 것입니다!:

/* Small integers are preallocated in this array so that they
   can be shared.
   The integers that are preallocated are those in the range
   -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive).
*/
static PyLongObject small_ints[NSMALLNEGINTS + NSMALLPOSINTS];

그래서 그래, 이건 우리의 남자 야. 새로운 것을 만들고 싶을 때 int 범위 안에서 [NSMALLNEGINTS, NSMALLPOSINTS) PrealLocated에서 이미 존재하는 객체에 대한 참조를 되 찾을 수 있습니다.

참조는 동일한 개체를 나타 내기 때문에 발행 id() 직접 또는 신원을 확인합니다 is 그것은 정확히 같은 것을 반환합니다.

그러나 그들은 언제 할당됩니까 ??

초기화 중 _PyLong_Init 파이썬은 기꺼이 a for 루프를 입력 할 것입니다.

for (ival = -NSMALLNEGINTS; ival <  NSMALLPOSINTS; ival++, v++) {
    // Look me up!
}

내 설명이 당신을 만들었 으면 좋겠다 C (분명히 의도 된) 지금 분명히.


그러나 257은 257입니까? 무슨 일이야?

이것은 실제로 설명하기가 더 쉽습니다. 그리고 나는 이미 그렇게하려고 시도했습니다; Python 이이 대화식 진술을 실행할 것이기 때문입니다.

>>> 257 is 257

단일 블록으로. 이 진술의 불만과 함께 Cpython은 두 개의 일치하는 리터럴을 가지고 있으며 PyLongObject 대표 257. 편집을 직접 수행하고 그 내용을 검사하면 이것을 볼 수 있습니다.

>>> codeObj = compile("257 is 257", "blah!", "exec")
>>> codeObj.co_consts
(257, None)

Cpython이 작업을 수행 할 때; 이제 똑같은 개체를로드 할 것입니다.

>>> import dis
>>> dis.dis(codeObj)
  1           0 LOAD_CONST               0 (257)   # dis
              3 LOAD_CONST               0 (257)   # dis again
              6 COMPARE_OP               8 (is)

그래서 is 돌아올 것입니다 True.


* - 나는 대부분의 것을 따라갈 수 있도록 더 소개하는 방식으로 이것을 시도하고 말할 것입니다.

체크인 할 수 있습니다 소스 파일 intobject.c, 파이썬은 효율성을 위해 작은 정수를 캐시합니다. 작은 정수에 대한 참조를 만들 때마다 새 개체가 아닌 캐시 된 작은 정수를 언급합니다. 257은 작은 정수가 아니므로 다른 물체로 계산됩니다.

사용하는 것이 좋습니다 == 그 목적을 위해.

나는 당신의 가설이 정확하다고 생각합니다. 실험 id (물체의 ID) :

In [1]: id(255)
Out[1]: 146349024

In [2]: id(255)
Out[2]: 146349024

In [3]: id(257)
Out[3]: 146802752

In [4]: id(257)
Out[4]: 148993740

In [5]: a=255

In [6]: b=255

In [7]: c=257

In [8]: d=257

In [9]: id(a), id(b), id(c), id(d)
Out[9]: (146349024, 146349024, 146783024, 146804020)

그 숫자가 보입니다 <= 255 리터럴로 취급되며 위의 모든 것은 다르게 취급됩니다!

ints, strings 또는 dateTimes와 같은 불변의 가치 객체의 경우 객체 아이덴티티가 특히 유용하지 않습니다. 평등에 대해 생각하는 것이 낫습니다. Identity는 본질적으로 가치 객체에 대한 구현 세부 사항입니다. 불변이 없기 때문에 동일한 객체 또는 여러 객체에 대한 여러 심판을 갖는 것 사이에는 효과적인 차이가 없습니다.

is ~이다 정체성 평등 연산자 (기능과 같은 기능 id(a) == id(b)); 두 개의 동일한 숫자가 반드시 같은 객체는 아닙니다. 성능의 이유로 일부 작은 정수가 발생합니다 메모 화 따라서 그들은 동일하게 경향이 있습니다 (이것은 불변이기 때문에 할 수 있습니다).

PHP === 반면, 운영자는 평등을 확인하고 유형을 확인하는 것으로 설명됩니다. x == y and type(x) == type(y) Paulo Freitas의 의견에 따라. 이것은 일반적인 숫자에 충분하지만 is 정의하는 수업의 경우 __eq__ 터무니없는 방식으로 :

class Unequal:
    def __eq__(self, other):
        return False

PHP는 분명히 "내장 된"클래스에 대해 동일한 것을 허용합니다 (PHP가 아닌 C 레벨에서 구현 된 것을 의미합니다). 약간 덜 터무니없는 사용은 타이머 객체 일 수 있으며, 숫자로 사용될 때마다 값이 다릅니다. 왜 당신이 Visual Basic의 에뮬레이션하고 싶은지 Now 그것이 평가라는 것을 보여주는 대신 time.time() 모르겠어요.

Greg Hewgill (OP)은 "내 목표는 가치의 평등보다는 대상 정체성을 비교하는 것입니다. 숫자를 제외하고는 객체 정체성을 가치의 평등과 동일하게 처리하려는 숫자를 제외하고는"

이것은 우리가 사물을 숫자로 분류해야하든 아니든 우리가 == 또는 is. CPYTHON 정의합니다 숫자 프로토콜, pynumber_check을 포함하여, 이것은 파이썬 자체에서 액세스 할 수 없습니다.

우리는 사용하려고 노력할 수 있습니다 isinstance 우리가 알고있는 모든 숫자 유형이 있지만 필연적으로 불완전합니다. 유형 모듈에는 stringTypes 목록이 있지만 숫자는 없습니다. Python 2.6 이후, 내장 번호 클래스에는 기본 클래스가 있습니다. numbers.Number, 그러나 동일한 문제가 있습니다.

import numpy, numbers
assert not issubclass(numpy.int16,numbers.Number)
assert issubclass(int,numbers.Number)

그런데, Numpy 낮은 숫자의 별도 인스턴스를 생성합니다.

나는이 질문 의이 변형에 대한 답을 실제로 모른다. 이론적으로 CTypes를 사용하여 전화 할 수 있다고 생각합니다 PyNumber_Check, 그러나 그 기능조차도 토론되었습니다, 그리고 그것은 확실히 휴대용이 아닙니다. 우리는 지금 우리가 테스트하는 것에 대해 덜 구체적이어야합니다.

결국,이 문제는 원래 Python에서 유래 한 트리가없는 파이썬에서 비롯됩니다. 계획 number?, 또는 Haskell 's 유형 클래스 숫자. is 가치 평등이 아닌 객체 아이덴티티를 점검합니다. PHP는 다채로운 역사를 가지고 있습니다 === 분명히 행동합니다 is 물체에서만 php5에서는 php4가 아닙니다. 언어를 가로 질러 움직이는 고통 (하나의 버전 포함)이 증가합니다.

기존 답변에서는 지적되지 않은 또 다른 문제가 있습니다. 파이썬은 두 가지 불변의 값을 병합 할 수 있으며 사전 창조 된 작은 int 값만이 발생할 수있는 유일한 방법은 아닙니다. 파이썬 구현은 결코 아닙니다 보장 이렇게하기 위해, 그러나 그들은 모두 작은 int 이상의 것을 위해 그것을합니다.


우선, 빈과 같은 다른 사전 만들어진 값이 있습니다. tuple, str, 그리고 bytes, 및 일부 짧은 줄 (Cpython 3.6에서는 256 개의 단일 문자 라틴어 -1 문자열입니다). 예를 들어:

>>> a = ()
>>> b = ()
>>> a is b
True

또한 비 임시 값조차도 동일 할 수 있습니다. 다음과 같은 예를 고려하십시오.

>>> c = 257
>>> d = 257
>>> c is d
False
>>> e, f = 258, 258
>>> e is f
True

그리고 이것은 제한되지 않습니다 int 값 :

>>> g, h = 42.23e100, 42.23e100
>>> g is h
True

분명히 Cpython은 사전 창조 된 것을 가지고 있지 않습니다 float 가치 42.23e100. 그래서 여기서 무슨 일이 일어나고 있습니까?

CPYTHON 컴파일러는 알려진 일부 상상할 수있는 유형의 일정한 값을 병합합니다. int, float, str, bytes, 동일한 컴파일 장치에서. 모듈의 경우 전체 모듈은 컴파일 장치이지만 대화식 통역사에서 각 문은 별도의 컴파일 장치입니다. 부터 c 그리고 d 별도의 명령문으로 정의되며 해당 값이 병합되지 않습니다. 부터 e 그리고 f 동일한 진술로 정의되며 해당 값이 병합됩니다.


바이트 코드를 분해하여 무슨 일이 일어나고 있는지 알 수 있습니다. 수행 한 함수를 정의해보십시오 e, f = 128, 128 그리고 전화 dis.dis 그것에, 당신은 단일 상수 값이 있음을 알 수 있습니다 (128, 128)

>>> def f(): i, j = 258, 258
>>> dis.dis(f)
  1           0 LOAD_CONST               2 ((128, 128))
              2 UNPACK_SEQUENCE          2
              4 STORE_FAST               0 (i)
              6 STORE_FAST               1 (j)
              8 LOAD_CONST               0 (None)
             10 RETURN_VALUE
>>> f.__code__.co_consts
(None, 128, (128, 128))
>>> id(f.__code__.co_consts[1], f.__code__.co_consts[2][0], f.__code__.co_consts[2][1])
4305296480, 4305296480, 4305296480

컴파일러가 저장된 것을 알 수 있습니다 128 바이트 코드에서 실제로 사용하지 않더라도 상수로 Cpython의 컴파일러가 얼마나 적은 지에 대한 아이디어를 제공합니다. 즉, (비어 없음) 튜플이 실제로 합병되지 않음을 의미합니다.

>>> k, l = (1, 2), (1, 2)
>>> k is l
False

그것을 함수에 넣고 dis 그것은 co_consts-거기에 1 그리고 a 2, 둘 (1, 2) 동일하게 공유하는 튜플 1 그리고 2 그러나 동일하지는 않지만 a ((1, 2), (1, 2)) 두 개의 뚜렷한 동일한 튜플이있는 튜플.


Cpython이하는 최적화가 하나 더 있습니다 : String Interning. 컴파일러 상수 폴딩과 달리 소스 코드 리터럴로 제한되지 않습니다.

>>> m = 'abc'
>>> n = 'abc'
>>> m is n
True

반면에, 그것은 str 유형 및 문자열에 내부 스토리지 종류 "ASCII Compact", "Compact"또는 "Legacy Ready", 그리고 많은 경우에만 "ASCII Compact"만 인턴이됩니다.


어쨌든, 값에 대한 규칙은 구현에서 구현에서 구현에 이르기까지, 동일한 구현의 버전간에, 동일한 구현의 동일한 사본에서 동일한 코드의 실행 사이에 달라질 수 없을 수 있습니다. .

재미를 위해 하나의 특정 파이썬에 대한 규칙을 배우는 것이 좋습니다. 그러나 코드에서 그들에게 의존 할 가치가 없습니다. 유일한 안전한 규칙은 다음과 같습니다.

  • 동일하지만 별도로 만들어진 불변의 값이 동일하다고 가정하는 코드를 작성하지 마십시오.
  • 동일하지만 별도로 만들어진 불변의 값이 두 개라고 가정하는 코드를 작성하지 마십시오.

또는 다시 말해서만 사용하십시오 is 문서화 된 싱글 톤을 테스트하기 위해 (예 : None) 또는 코드의 한 곳에서만 생성됩니다 (예 : _sentinel = object() 관용구).

또한 문자열에서도 발생합니다.

>>> s = b = 'somestr'
>>> s == b, s is b, id(s), id(b)
(True, True, 4555519392, 4555519392)

이제 모든 것이 괜찮아 보입니다.

>>> s = 'somestr'
>>> b = 'somestr'
>>> s == b, s is b, id(s), id(b)
(True, True, 4555519392, 4555519392)

그것도 기대됩니다.

>>> s1 = b1 = 'somestrdaasd ad ad asd as dasddsg,dlfg ,;dflg, dfg a'
>>> s1 == b1, s1 is b1, id(s1), id(b1)
(True, True, 4555308080, 4555308080)

>>> s1 = 'somestrdaasd ad ad asd as dasddsg,dlfg ,;dflg, dfg a'
>>> b1 = 'somestrdaasd ad ad asd as dasddsg,dlfg ,;dflg, dfg a'
>>> s1 == b1, s1 is b1, id(s1), id(b1)
(True, False, 4555308176, 4555308272)

이제는 예상치 못한 일입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top