Почему присвоение True / False не работает, как я ожидаю? - PullRequest
32 голосов
/ 13 января 2010

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

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.

Ответы [ 5 ]

76 голосов
/ 13 января 2010

Python имеет эти два (среди прочих) встроенных объекта. Они просто объекты; в начале у них еще нет имен, но чтобы знать, к чему мы обращаемся, давайте назовем их 0x600D и 0xBAD.

Перед началом выполнения скрипта Python (2.x) имя 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, и мир снова становится хорошим.

43 голосов
/ 13 января 2010

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

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.

18 голосов
/ 13 января 2010

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

12 голосов
/ 13 января 2010

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

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

Поскольку это не так (в моей версии), присвоение True = False означает, что «True» - это еще одно «переменное» имя.

0 голосов
/ 21 апреля 2016

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

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

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

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