2014-10-09 2 views
8

при создании набора:Почему python устанавливает только False и Zero?

>>> falsey_set = {0, '', False, None} # set([False, '', None]) 
>>> falsey_set = {False, '', 0, None} # set([0,'', None]) 
>>> # adding an item to the set doesn't change anything either 
>>> falsey_set.add(False) # set([0,'',None]) 

или словарь, который имитирует поведение несколько:

>>> falsey_dict = {0:"zero", False:"false"} # {0:'false'} # that's not a typo 
>>> falsey_dict = {False:'false', 0:'zero'} # {False: 'zero'} # again, not a typo 
>>> falsey_set.add(()) # set([0,'', None,()]) 
>>> falsey_set.add({}) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unhashable type: 'dict' 
>>> falsey_dict[()] = 'list' # {False:'zero',():'list'} 
>>> falsey_dict({}) = 'dict' 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unhashable type: 'dict' 

0 и False всегда вынимайте друг друга из набора. В словарях они совершенно неверны. Есть ли причина для этого? Хотя я понимаю, что булевы производятся из целых чисел в Python. Что такое питоновское рассуждение для того, чтобы действовать таким образом в контексте множеств в определенном смысле (я не слишком люблю словари)? Так как в то время как полезно в truthy сравнения, как:

>>> False == 0 # True 

Существует очевидное значение в дифференциации:

>>> False is 0 # False 

Я смотрел по documentation и не могу найти ссылку на поведение

Update

@de lnan Я думаю, вы попали в гвоздь на голове с детерминизмом хэша, о котором вы упоминали в комментариях. Как отмечает @mgilson какFalse и 0 использовать ту же функцию хэширования, однако так делать object и многие из его подклассов (т.е .: super), которые имеют одинаковые хэш-функции. Кажется, что ключ находится во фразе Hashable objects which compare equal must have the same hash value от documentation. Поскольку False == 0 и оба они хешируемые, их выходы должны быть определены Python равными. Наконец, в определении hashable указано, как наборы используют хешируемость в множестве членства со следующим: Hashability makes an object usable as a dictionary key and a set member, because these data structures use the hash value internally. Хотя я до сих пор не понимаю, почему они оба используют одну и ту же функцию хеширования - я могу согласиться с этим.

Если мы все согласны, тогда кто-то предложит отполированный ответ, и я его приму. Если может быть какое-то улучшение, или если я не в базе, пожалуйста, сообщите ниже.

+0

Зачем нужна идентификация? Две равные строки могут иметь разные тождества, представьте себе боль, если они считаются различными по наборам и диктофонам. Также обратите внимание, что по определению hashability, 'hash (x) == hash (y)' ** должен ** выполняться, когда 'x == y'. – delnan

+0

Связанный вопрос: http://stackoverflow.com/questions/2764017/is-false-0-and-true-1-in-python-an-implementation-detail-or-is-it-guarante. –

+1

Вы не должны слишком зависеть от хэширующей части этого; это в основном не имеет значения.Простой ответ заключается в том, что членство в dict и set (и list, come to that) основано на * равенстве * (если вы не хотите nitpick, и в этом случае лучшее описание - это идентификация-то-равенство), а так как 'False == 0', они считаются одинаковыми при использовании в качестве заданных элементов или клавиш словаря. Тот факт, что dicts и sets использует хэш-таблицу (и, следовательно, ключи и элементы должны быть хешируемыми, а равенство должно подразумевать равенство хэшей) является вторичным. –

ответ

3

Это потому, что False и 0хэш к тому же значению и равны.

Причина, по которой они хэш с тем же значением, потому что bool подкласс int так bool.__hash__ просто вызывает те же, лежащие в основе механики, int.__hash__ звонки ...

>>> bool.__hash__ is int.__hash__ 
True 
+1

Если они равны и [хешируются] (https://docs.python.org/3/glossary.html#term-hashable), они * должны * хэш с тем же значением. @RogerFan – delnan

+0

@ delnan - Не совсем. Довольно легко приготовить надуманный пример, где два хэша объектов имеют одно и то же значение, но не равны ... – mgilson

+0

Я думаю, что споры по подклассу отношения ставят телегу перед лошадью. 'True 'и' False' предназначены для целых чисел 1 и 0 с разными 'repr()', поэтому они реализованы как подкласс 'int'. – delnan

0

Во-первых, давайте попробуем объяснить, что происходит в начале, с вашими falsey_set и falsey_dict, так что вы видите, что это не «неправильно», а на самом деле только возможное согласованное решение. Для этого мы временно удалим bool с картинки и используем то, что интуитивно понимает больше людей: десятичные числа.

>>> numset = {3, 5, 3.0, 4} # {3.0, 4, 5} 
>>> numset.add(3)   # no change 

Я надеюсь, вы согласитесь, что это именно то, как set должно работать.Если вы этого не сделаете, то кажется, что либо вы думаете, что 3 и 3.0 на самом деле не равны, или вы думаете, что для набора должно быть разрешено иметь равные элементы. Ни то, ни другое не являются действительно продуктивными убеждениями ИМО.

(конечно, , который один из 3 и 3,0 заканчивается в комплекте, является вопросом обработки дисплеев, а набор немного странный, поскольку он является атрофированным dict, где ключ и значение одинаковы. последовательна и указано в Pythton точка сейчас есть, конечно, они не могут как быть в комплекте)

еще один момент:.. как вы видите, что я могу добавить многие другие истинные вещи в моем наборе (как 4 и 5) не имеет значения. То же самое, факт, что вы можете добавить много других ложных вещей в свой набор (например, '' и None), совсем не имеет значения. Истина - красная селедка. Набор может иметь истинные элементы и ложные элементы. Что не может быть, это равно элементов.

>>> numdict = {3:"a", 3.0:"b"} # {3:"b"} 

Это выглядит страннее на первый взгляд, но на самом деле гораздо более ясной, что происходит, так как ключи и значения разделены. правила Python являются точными: чтение Dict дисплей слева направо, возьмите каждую пару : б, а затем, если ключевой уже в Словаре, обновить его значение б, иначе вставить ключ в dict со значением b.

С помощью этого алгоритма, я думаю, очевидно, что окончательный фикт заканчивается так, и все остальные действия, которые вы заметили. Важно то, что, как и в наборе, то, что вам нужно действительно нужно в dict, чтобы иметь только одно значение для любого заданного ключа. Наличие двух равных ключей в одном и том же диктове было бы приглашением на катастрофу, так как тогда вы сможете присвоить им разные значения.

Итак, в двух словах: я думаю, вы слишком глубоко выкопали себя с помощью функций хэша и других элементов реализации. Это прекрасный способ увидеть как Python делает X, раз вы понимаете, что X - это правильная вещь. Но сначала вы должны увидеть, что X - это правильная вещь. И я надеюсь, что я показал тебе это сейчас. Набор не может иметь равные элементы. Это победит широко используемую цель набора, удалив дубликаты. И 3 и 3.0 действительно равны. Это не имеет ничего общего с типами, некоторые вложения настолько естественны, что мы их стерли на математическом уровне.

Конечно, это оставляет вопрос «почему 0 и False действительно равны»? На самом деле, ответ не совсем по-другому: просто еще одно математически стираемое вложение, которое так невероятно полезно, нам придется перепрыгнуть через многие смешные обручи без него. Подробнее об этом читайте о скобке Айверсона. ;-) Но в любом случае, кажется, вы знаете об этой части. Выше было то, что было проблематично, я думаю.

Смежные вопросы