2016-05-04 5 views
26

Ich habe folgendes WörterbuchPython-Wörterbuch hat nicht alle zugeordneten Tasten oder Elemente

exDict = {True: 0, False: 1, 1: 'a', 2: 'b'} 

und wenn ich exDict.keys() drucken, na ja, es gibt mir einen Generator an. Ok, also zwinge ich es zu einer Liste, und es gibt mir

[False, True, 2] 

Warum ist nicht 1 dort? Wenn ich exDict.items() drucken gibt es mir

[(False, 1), (True, 'a'), (2, 'b')] 

Wer eine Vermutung über das, was hier vor sich geht? Ich bin ratlos.

+2

Schöner Kopf-Scratcher! Pythons Designer versuchen, Überraschungen zu vermeiden, aber Sie können sie nicht alle bekommen ... – alexis

+3

Sie haben die Lösung in Ihren Elementen: '(True, 'a')', was der Wert für '1' ist. – njzk2

Antwort

28

Das passiert, weil True == 1 (und False == 0, aber Sie hatten 0 nicht als Schlüssel). Sie werden irgendwie Code oder Daten Refactoring müssen, weil ein dict Schlüssel hält gleich sein, wenn sie „gleich“ (statt is) sind.

+0

Aber es gibt keine Gewissheit, welche man zeigen würde, da das Diktat ungeordnet ist, oder? – heemayl

+1

Ich bin mir nicht sicher, ob es Gewissheit gibt. Ich würde mich sowieso nicht darauf verlassen. –

+1

@heemayl Obwohl die Reihenfolge der Elemente in einem Diktat nicht garantiert ist, denke ich, dass der Schlüssel, den er verwendet, der erste sein wird, auf den er trifft. Es wird einen Schlüssel nicht ersetzen, wenn er einen vorhandenen Schlüssel findet, der gleichwertig ist. –

12

Was Sie sehen, ist Python, der die 1 gleich der True wird.

Sie werden sehen, dass das Wörterbuch Sie drucken ist:

False 1 
True a 
2  b 

Wenn der Wert a gemeint war der 1 zugeordnet werden, sondern der Wert für True gewöhnte sich an a neu zugewiesen.

Nach der Python 3 Documentation:

Die Booleschen Typ ist ein Subtyp des Integer-Typ und Boolesche Werte verhalten sich wie die Werte 0 und 1 bzw. in fast allen Kontexten, wobei der Ausnahme, dass Wenn sie in einen String konvertiert werden, werden die Strings "False" bzw. "True" zurückgegeben.

Hervorhebung von mir.

Hinweis: In Python 2.X True und False kann neu zugewiesen werden, so dass dieses Verhalten nicht garantiert werden kann.

5

Python nehmen Sie die 1 als True. Und der Booleschen Typ ist ein Subtyp des Integer-Typs

In [1]: a = {} 

In [2]: a[True] = 0 

In [3]: 1 in a.keys() 
Out[3]: True 
2

Wenn Sie ein Schlüssel-Wert-Paar stecken in einer dict Python prüft, ob der Schlüssel bereits vorhanden ist, und wenn es vorhanden ist, wird es den aktuellen Wert zu ersetzen.

Diese Prüfung macht etwas wie folgt aus:

def hash_and_value_equal(key1, key2): 
    return hash(key1) == hash(key2) and key1 == key2 

So müssen nicht nur die Werte gleich sein, sondern auch ihre hash.Leider für Sie True und 1 sondern auch False und 0 werden gleiche Schlüssel berücksichtigt werden:

>>> hash_and_value_equal(0, False) 
True 

>>> hash_and_value_equal(1, True) 
True 

und daher ersetzen sie den Wert (aber nicht der Schlüssel):

>>> a = {1: 0} 
>>> a[True] = 2 
>>> a 
{1: 2} 

>>> a = {False: 0} 
>>> a[0] = 2 
>>> a 
{False: 2} 

zeigte ich habe Der Fall eines manuellen Hinzufügens eines Schlüssels, aber die durchgeführten Schritte sind die gleichen, wenn dict literal:

verwendet wird

oder die dict -builtin:

>>> a = dict(((0, 0), (False, 2))) 
>>> a 
{0: 2} 

Dies kann sehr wichtig sein, wenn Sie eigene Klassen schreiben und wollen, dass sie als mögliche Schlüssel in Wörterbücher verwenden. Je nach Implementierung von __eq__ und __hash__ diesem Willen und die Werte der gleichen, aber nicht identischer Schlüssel nicht ersetzen:

class IntContainer(object): 
    def __init__(self, value): 
     self.value = value 

    def __eq__(self, other): 
     return self.value == other 

    def __hash__(self): 
     # Just offsetting the hash is enough because it also checks equality 
     return hash(1 + self.value) 

>>> hash_equal(1, IntContainer(1)) 
False 

>>> hash_equal(2, IntContainer(1)) 
False 

diese wird also nicht ersetzen bestehende ganzzahlige Schlüssel:

>>> a = {1: 2, IntContainer(1): 3, 2: 4} 
>>> a 
{1: 2, <__main__.IntContainer at 0x1ee1258fe80>: 3, 2: 4} 

oder etwas daß als identisch betrachtet Schlüssel:

class AnotherIntContainer(IntContainer): 
    def __hash__(self): 
     # Not offsetted hash (collides with integer) 
     return hash(self.value) 

>>> hash_and_value_equal(1, AnotherIntContainer(1)) 
True 

Diese werden nun die ganze Zahl Tasten ersetzen:

Die einzige wirklich wichtige Sache ist zu bedenken, dass Dictionary Keys gleichwertig sind, wenn die Objekte und ihr Hash gleich sind.

Verwandte Themen