Оператор "є" поводиться несподівано з цілими числами


509

Чому наступне поводиться несподівано в 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, виявляється, що Python 2.3.3 показує вищезгадану поведінку між 99 і 100.

Виходячи з вищесказаного, я можу припустити, що Python внутрішньо реалізований таким чином, що "малі" цілі числа зберігаються інакше, ніж великі цілі числа, і isоператор може визначити різницю. Чому протікає абстракція? Що є кращим способом порівняння двох довільних об’єктів, щоб побачити, чи однакові вони, коли я не знаю заздалегідь, чи це числа чи ні?


1
Подивіться тут > Поточна реалізація зберігає масив цілих об'єктів для всіх> цілих чисел від -5 до 256, коли ви створюєте int в цьому діапазоні, ви фактично просто повертаєте посилання на існуючий об'єкт.
користувач5319825

2
Це специфічна для CPython деталь реалізації та невизначена поведінка, використовуйте з обережністю
ospider

Відповіді:


392

Погляньте на це:

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

Ось, що я знайшов у документації на Python 2, "Прості об'єкти цілих чисел" (це саме для Python 3 ):

Поточна реалізація зберігає масив цілих об'єктів для всіх цілих чисел між -5 і 256, коли ви створюєте int в цьому діапазоні, ви фактично просто отримуєте посилання на існуючий об'єкт. Тож має бути можливість змінити значення 1. Я підозрюю, що поведінка Python у цьому випадку не визначена. :-)


46
хтось знає, як обрано цей діапазон (-5, 256)? я б не надто здивувався, якби це було (0, 255) або навіть (-255, 255), але діапазон 262 чисел, починаючи з -5, здається напрочуд довільним.
Вудро Барлоу

6
@WoodrowBarlow: Я думаю, що -5 - це просто евристика, що дозволяє зафіксувати загальні негативні заповнювачі. 0..255 охоплює масиви однобайтових значень. Це 256 загадково, але я думаю, що це (для) збирання цілих чисел у / з байтів.
Девіс-Оселедець

3
З того, що я розумію, діапазон був обраний, переглянувши загальновживані значення для кількох проектів (та декількох мов).
Tony Suffolk 66,

9
За даними reddit.com/r/Python/comments/18leav/… , колишній діапазон становив [-5,100]. Він був розширений, щоб включити повний діапазон значень байтів - плюс 256, оскільки це, мабуть, загальне число.
mwfearnley

2
@Ashwani спробуйте прочитати коментарі біля вашого коментаря, розміщеного за два роки до вашого, і ви знайдете відповідь на своє запитання.
jbg

116

Оператор Python "є" поводиться несподівано з цілими числами?

Підводячи підсумок - дозвольте підкреслити: не використовуйте 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) є місцем у пам'яті, є деталлю реалізації. Інші реалізації 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є однаковими цілими екземплярами. Цілі особи незмінні в Python, тому вони не можуть змінюватися. Це не повинно впливати на будь-який код. Цього не слід очікувати. Це лише деталь реалізації.

Але, можливо, ми повинні бути раді, що в пам'яті немає нового окремого екземпляра кожного разу, коли ми констатуємо значення, що дорівнює 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 намагається бути розумною і не створювати надмірно оцінені цілі числа в пам'яті, якщо цього не потрібно. Ви, схоже, вказуєте, що використовуєте референтну реалізацію Python, що є CPython. Добре для CPython.

Можливо, ще краще, якщо CPython міг би зробити це в усьому світі, якщо це могло б зробити це дешевше (як це буде коштувати в пошуку), можливо, може бути інша реалізація.

Але що стосується впливу на код, то вам не варто буде байдуже, чи є ціле число певним екземпляром цілого числа. Вам слід дбати лише про те, яке значення має цей примірник, і ви використовували для цього звичайні оператори порівняння, тобто ==.

Що isробить

isперевіряє, що idдва об'єкти однакові. У CPython id- це місце в пам'яті, але це може бути якийсь інший однозначно ідентифікаційний номер в іншій реалізації. Щоб відновити це з кодом:

>>> a is b

те саме, що

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

Чому б ми хотіли isтоді використовувати ?

Це може бути дуже швидким перевіркою відносно сказаного, перевіряючи, чи мають дві дуже довгі рядки значення. Але оскільки це стосується унікальності об'єкта, ми маємо для цього обмежені випадки використання. Насправді ми здебільшого хочемо використовувати його для перевірки None, що таке синглтон (єдиний екземпляр, що існує в одному місці в пам'яті). Ми можемо створити інші одиночні кнопки, якщо є потенціал їх поєднання, що ми можемо перевірити is, але вони відносно рідкісні. Ось приклад (буде працювати в 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- не використовуйте його для перевірки рівності цілих чисел, рядків, кортежів тощо." Однак я намагаюся інтегрувати просту машину стану у свій клас, і оскільки стани - це непрозорі значення, єдине спостережуване властивість яких - тотожність або ідентичність, то для них виглядає цілком природно порівняння is. Я планую використовувати інтерновані рядки як держави. Я віддав перевагу простим цілим числам, але, на жаль, Python не може інтернувати цілі числа ( 0 is 0це деталізація реалізації).
Олексій

@ Алекс звучить так, що тобі потрібні перерахунки? stackoverflow.com/questions/37601644/…
Aaron Hall

Можливо, дякую, про них не знав. Це може бути відповідним доповненням до Вашого відповіді на ІМО.
Олексій

Можливо, використання такої кількості тупих предметів, як дозорний у вашій відповіді, було б
Олексій

Перерахунки @Alexey є у стандартній бібліотеці Python 3, і це, ймовірно, спонукає ваш код бути дещо змістовнішим, ніж голі дозорці.
Аарон Холл

60

Це залежить від того, чи шукаєте ви, чи є дві речі рівними, або той самий об'єкт.

isперевіряє, чи є вони однаковим об'єктом, а не просто рівним. Невеликі вкладки, ймовірно, вказують на те саме місце пам'яті для економії простору

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

Ви повинні використовувати ==для порівняння рівності довільних об'єктів. Ви можете вказати поведінку за допомогою __eq__та __ne__атрибутів.


Великі пальці, щоб насправді пояснити, як порівнювати довільні об’єкти, як запитував ОП !!
Joooeey

54

Я спізнююсь, але ви хочете отримати джерело зі своєю відповіддю? Я спробую сказати це у вступному порядку, щоб більше людей могли слідувати далі.


Хороша річ у CPython - це те, що ви можете насправді бачити джерело для цього. Я збираюся використовувати посилання для версії 3.5 , але знайти відповідні 2.x - тривіально.

У CPython є функцією C-API, яка обробляє створення нового intоб'єкта PyLong_FromLong(long v). Опис цієї функції:

Поточна реалізація зберігає масив цілих об'єктів для всіх цілих чисел між -5 і 256, коли ви створюєте int в цьому діапазоні, ви фактично просто отримуєте посилання на існуючий об'єкт . Тож має бути можливість змінити значення 1. Я підозрюю, що поведінка Python у цьому випадку не визначена. :-)

(Мій курсив)

Не знаю про вас, але я бачу це і думаю: Давайте знайдемо цей масив!

Якщо ви не зіткнулися з кодом С, що реалізує CPython, вам слід ; все досить організовано і читабельно. Для нашого випадку, ми повинні дивитися в Objectsпідкаталозі з основного вихідного коду дерева каталогів .

PyLong_FromLongмає справу з longпредметами, тому не повинно бути важко зробити висновок, що нам потрібно зазирнути всередину longobject.c. Заглянувши всередину, ви можете подумати, що речі хаотичні; вони є, але не бійтеся, функція, яку ми шукаємо, охолоджує на лінії 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);

Гаразд, оголосити "А" 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)ви просто отримаєте посилання на вже наявний об'єкт, який був попередньо виділений.

Оскільки посилання стосується одного і того ж об'єкта, видача id()безпосередньо або перевірка на тотожність isна ньому поверне точно те саме.

Але, коли вони виділяються ??

Під час ініціалізації в_PyLong_Init Python із задоволенням ввійдете в цикл for зробіть це для вас:

for (ival = -NSMALLNEGINTS; ival <  NSMALLPOSINTS; ival++, v++) {

Перевірте джерело, щоб прочитати тіло циклу!

Я сподіваюсь, що моє пояснення зрозуміло, що ви зараз зрозуміли C ( речі, очевидно, навмисні)


Але 257 is 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.


37

Як ви можете перевірити у вихідному файлі intobject.c , Python кешує невеликі цілі числа для ефективності. Кожен раз, коли ви створюєте посилання на мале ціле число, ви посилаєтесь на кешоване мале ціле число, а не на новий об'єкт. 257 не є малим цілим числом, тому воно обчислюється як інший об'єкт.

Краще використовувати ==для цієї мети.


19

Я думаю, що ваші гіпотези правильні. Експериментуйте з 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трактуються як буквальні, а все, що вище, трактується по-різному!


1
Це тому, що об’єкти, що представляють значення від -5 до +256, створюються під час запуску - і тому все використання цих значень використовується для попередньо побудованого об'єкта. Майже всі посилання на цілі числа поза цим діапазоном створюють новий внутрішній об'єкт щоразу, коли на них посилаються. Я думаю, що використання терміна literal є заплутаним - буквально зазвичай посилається на будь-яке значення, яке вводиться у фрагменті коду, - тому все число у вихідному коді є літералами.
Tony Suffolk 66,

13

Для об'єктів, що не змінюються, такі як ints, string або datetimes, ідентичність об'єкта не особливо корисна. Краще думати про рівність. Ідентичність - це фактично деталь реалізації для ціннісних об'єктів - оскільки вони незмінні, немає ефективної різниці між наявністю кількох рефлексив на один і той же об'єкт або декілька об'єктів.


12

Є ще одне питання, яке не вказано в жодній із існуючих відповідей. Python дозволено об'єднати будь-які два незмінні значення, а попередньо створені малі значення int - це не єдиний спосіб, як це може відбутися. Реалізація Python ніколи не гарантує цього, але всі вони роблять це для більше, ніж просто невеликі вкладки.


З одного боку, є деякі інші заздалегідь створені значення, такі як порожні tuple, strта bytesта деякі короткі рядки (у CPython 3.6 це 256 односимвольних рядків Latin-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- є a 1і a 2, два (1, 2)кортежі, які поділяють одне 1і те ж, 2але не однакові, і ((1, 2), (1, 2))кортеж, який має два чітко рівних кортежа.


Є ще одна оптимізація, яку робить CPython: струнне інтернування. На відміну від постійного складання компілятора, це не обмежується лише літералами вихідного коду:

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

З іншого боку, він обмежений strтипом, а рядки внутрішнього типу зберігання "ascii compact", "compact" або "legacy ready" , і в багатьох випадках інтернірується лише "ascii compact".


У будь-якому випадку правила того, які значення повинні бути, можуть бути або не можуть бути різними, залежать від реалізації до реалізації та між версіями тієї ж реалізації, а може бути, навіть між запусками одного і того ж коду на одній копії тієї ж реалізації .

Це може бути варто вивчити правила для одного конкретного Python для задоволення. Але покладатися на них у коді не варто. Єдине безпечне правило:

  • Не пишіть код, який передбачає два однакових, але створені окремо незмінні значення, однакові (не використовуйте x is y, не використовуйте x == y)
  • Не пишіть код, який передбачає два рівні, але окремо створені незмінні значення, є різними (не використовуйте x is not y, не використовуйте x != y)

Або, іншими словами, використовувати лише isдля тестування документально підтверджених синглонів (наприклад None) або створених лише в одному місці коду (як _sentinel = object()ідіома).


Менш виразна порада проста: не використовуйте x is yдля порівняння, використання x == y. Так само не використовуйте x is not y, використовуйтеx != y
smci

Тож дивлячись на це запитання , чому стоїть a=257; b=257на одній лінії a is bTrue
Джо

8

is є оператором рівності ідентичності (функціонує як id(a) == id(b)); це просто те, що два рівних числа не обов'язково є одним і тим же об'єктом. З міркувань продуктивності деякі невеликі цілі числа запам'ятовуються, тому вони, як правило, однакові (це можна зробити, оскільки вони незмінні).

===Оператор PHP , з іншого боку, описується як перевірка рівності та типу: x == y and type(x) == type(y)відповідно до коментаря Пауло Фрейтаса. Цього буде достатньо для загальних чисел, але вони відрізняються від isкласів, які визначають __eq__абсурдно:

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

PHP, мабуть, дозволяє те ж саме для "вбудованих" класів (я вважаю, реалізованих на рівні C, а не на PHP). Трохи менш абсурдне використання може бути тимчасовим об'єктом, який має різне значення кожного разу, коли його використовують як число. Чому б ви хотіли наслідувати Visual Basic Nowзамість того, щоб показувати, що це оцінка з time.time()не знаю.

Грег Х'югілл (ОП) зробив один уточнюючий коментар "Моя мета - порівняння ідентичності об'єкта, а не рівність значення. За винятком цифр, де я хочу ставитись до ідентичності об'єкта так само, як до рівності значення".

Це матиме ще одну відповідь, оскільки ми маємо класифікувати речі як числа чи ні, щоб вибрати, чи порівнюємо ми з ==чи is. CPython визначає протокол числа , включаючи PyNumber_Check, але це не є доступним від самого Python.

Ми могли б спробувати використовувати isinstanceвсі типи чисел, які ми знаємо, але це неминуче було б неповним. Модуль типів містить список StringTypes, але немає NumberTypes. Починаючи з 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, який спочатку не мав дерева типів з предикатами, такими як Scheme number? або Haskell's type type Num . isперевіряє ідентичність об'єкта, а не цінність рівності. PHP також має барвисту історію, де, ===мабуть, поводиться як isлише на об'єктах PHP5, але не на PHP4 . Такими є зростаючі болі від пересування між мовами (включаючи версії однієї).


4

Так само буває і з рядками:

>>> 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)

Тепер це несподівано.


Відбулося це - погодився, що навіть дивніше. Тож я грав з цим, і це ще дивніше - пов'язане з космосом. Наприклад, рядок 'xx'такий, як очікувалося, як і є 'xxx', але 'x x'ні.
Брайан

2
Це тому, що він схожий на символ, якщо в ньому немає місця. Імена автоматично інтерновані, тому якщо xxу вашому сеансі Python в будь-якому місці є ім’я , ця рядок вже інтернована; і може бути евристик, який робить це, якщо він просто нагадує ім'я. Як і з числами, це можна зробити, оскільки вони незмінні. docs.python.org/2/library/functions.html#intern guilload.com/python-string-interning
Ян Верньє

3

Що нового в Python 3.8: зміни в поведінці Python :

Тепер компілятор виробляє SyntaxWarning, коли перевірки ідентичності ( isі is not) використовуються з певними типами літералів (наприклад, рядків, ints). Вони часто можуть працювати випадково в CPython, але це не гарантується мовою. Попередження радить користувачам використовувати замість тестів рівності ( == та !=).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.