2010-08-11 12 views
34

Ich bin daran interessiert, ein beliebiges Diktat zu nehmen und es in ein neues Diktat zu kopieren, es auf dem Weg zu mutieren.Fragen "ist hashable" über einen Python-Wert

Eine Mutation, die ich tun möchte, ist Schlüssel und Wert zu tauschen. Leider sind einige Werte selbstbestimmt. Dies erzeugt jedoch einen Fehler "nicht ausdehnbarer Typ: 'dict'". Es macht mir nichts aus, nur den Wert zu stringulieren und ihm den Schlüssel zu geben. Aber, ich möchte in der Lage sein, so etwas zu tun:

for key in olddict: 
    if hashable(olddict[key]): 
    newdict[olddict[key]] = key 
    else 
    newdict[str(olddict[key])] = key 

Gibt es eine saubere Art und Weise, dies zu tun, dass nicht eine Ausnahme beinhalten Einfangen und Analysieren des Nachrichtenzeichenfolge für „unhashable Typ“ ?

Antwort

38

Seit Python 2.6 können Sie die abstrakte Basisklasse verwenden collections.Hashable:

import collections 
>>> isinstance({}, collections.Hashable) 
False 
>> isinstance(0, collections.Hashable) 
True 

Dieser Ansatz wird auch in der Dokumentation erwähnt kurz für __hash__.

Doing so means that not only will instances of the class raise an appropriate TypeError when a program attempts to retrieve their hash value, but they will also be correctly identified as unhashable when checking isinstance(obj, collections.Hashable) (unlike classes which define their own __hash__() to explicitly raise TypeError).

+6

Funktioniert das, wenn ein Tupel eine Liste/ein Wörterbuch enthält? –

+4

Nein, und das können Sie nur zur Laufzeit feststellen, da zuvor der Inhalt einer Liste allgemein unbekannt ist. 'hash (([],))' gibt 'TypeError: nicht hashbarer Typ: 'list'' – Syncopated

+1

Kleine Warnung für Leute, die Python 2.7 benutzen' isinstance (bytearray ([0xa]), collections.Hashable)) '' '' gibt '' zurück 'hash (bytearray ([0xa]))' scheitert mit 'TypeError: nicht hashbarer Typ: 'bytearray''. – RedX

13
def hashable(v): 
    """Determine whether `v` can be hashed.""" 
    try: 
     hash(v) 
    except TypeError: 
     return False 
    return True 
+3

Ned - das ist genau das, was ich lieber vermeiden würde. Diese Funktion wird auch TypeErrors fangen, die nicht "nicht hashable type" sind. –

+5

Es gibt nur einen TypeError, der von hash() ausgelöst wird. Oder, was auch immer der TypeError-Hashwert anhebt, so wird Ihr Wert nicht gehashed. Ich würde sogar argumentieren, dass dies Exception einfangen sollte, weil es nicht wirklich wichtig ist, warum hash() fehlgeschlagen ist: ein Fehler in hash() macht Ihren Wert nicht abhebbar. Kannst du mehr darüber sagen, warum du solche Ausnahmen vermeiden willst? Dies kapselt die Exception-Behandlung in einer netten Funktion und lässt Ihren obigen Beispiel-Code perfekt funktionieren. –

+1

Vielleicht ist es eher ein philosophischer Punkt - die Frage ist nicht die "außergewöhnliche Bedingung", wegen einer Art "Freak-Bedingung" nicht aushaspbar zu sein, sondern eine Frage nach der Funktionalität, die auf einem Typ verfügbar ist. Wenn das irgendeinen Sinn ergibt. –

1

Alle in Python-Objekten integrierten, hashbaren Objekte verfügen über eine .__hash__()-Methode. Du kannst das überprüfen.

olddict = {"a":1, "b":{"test":"dict"}, "c":"string", "d":["list"] } 

for key in olddict: 
    if(olddict[key].__hash__): 
     print str(olddict[key]) + " is hashable" 
    else: 
     print str(olddict[key]) + " is NOT hashable" 

Ausgang

1 is hashable 
string is hashable 
{'test': 'dict'} is NOT hashable 
['list'] is NOT hashable 
+1

Eine Warnung dazu: In Python 2.5 wird dies geben:' { 'test': 'dict'} ist hashbar.Es kann in neueren Versionen auch ein falsches Ergebnis liefern, wenn eine Klasse '__hash__' definiert, um einen TypeError auszulösen. –

0

Warum nicht Duck Typing verwenden?

for key in olddict: 
    try: 
     newdict[olddict[key]] = key 
    except TypeError: 
     newdict[str(olddict[key])] = key