Подтвердить что ты не робот

Почему назначение True/False не работает, как я ожидаю?

Как часть ответа на другой вопрос, я написал следующий код, поведение которого на первый взгляд кажется странным:

print True                    # outputs true
True = False;    print True   # outputs false
True = True;     print True   # outputs false
True = not True; print True   # outputs true

Может ли кто-нибудь объяснить это странное поведение? Я думаю, что это имеет какое-то отношение к объектной модели Python, но я не уверен.

Это версия 2.5.2 под Cygwin.

4b9b3361

Ответ 1

У Python есть два (среди прочих) встроенных объектов. Это просто объекты; в начале у них пока нет имен, но чтобы знать, о чем мы говорим, позвоните им 0x600D и 0xBAD.

Перед запуском Python (2.x) script имя True привязывается к объекту 0x600D, а имя False привязывается к объекту 0xBAD, поэтому, когда программа ссылается на True, она смотрит на 0x600D.

Поскольку 0x600D и 0xBAD знают, что они обычно используются именами True и False, то, что они выводят при печати, т.е. метод __str__ 0x600D возвращает 'True' и т.д.

True = False

теперь связывает имя True с другим объектом. Отныне оба имени True и False относятся к одному и тому же объекту 0xBAD, который при печати выводит False.

True = True

ничего не делает: он принимает объект, на который ссылается имя True, и связывает новое (и старое) имя True с этим объектом. Поскольку (из-за предыдущего шага) True относится к 0xBAD до этого, он по-прежнему относится к 0xBAD после этого. Следовательно, печать все еще выводит False.

True = not True

сначала берет объект, к которому привязано имя True, которое равно 0xBAD. Он предоставляет этот объект оператору not. not не заботится (или знает), какое имя используется здесь для обозначения 0xBAD, оно просто знает, что при задании 0xBAD он должен возвращать 0x600D. Это возвращаемое значение затем присваивается оператору присваивания =, привязывая к этому объекту имя True.

Так как имя True теперь еще раз ссылается на объект 0x600D, вызов print True выводит True, и мир снова хорош.

Ответ 2

Представьте себе это:

A = True
B = False

print A           # true
A = B;  print A   # false
A = A;  print A   # false, because A is still false from before
A = not A; print A # true, because A was false, so not A is true

То же самое происходит, но в вашей версии это запутывает, потому что вы не ожидаете, что можете переопределить True и False.

Ответ 3

В 2.x, True и False не являются ключевыми словами, поэтому можно затенять встроенные модули таким образом.

Ответ 4

Вы можете проверить, является ли True/False ключевым словом:

>>> import keyword
>>> keyword.iskeyword('True')
False

Так как это не (в моей версии), назначение True = False просто означает, что "True" - это другое имя переменной.

Ответ 5

Вы можете легко восстановить исходные значения с помощью простых булевых сравнений:

True = 1==1
False = 1==0

Или путем преобразования целочисленных литералов в bools:

True = bool(1)  # actually every number except 0 works
False = bool(0)