Python: TypeError: nicht zerlegbarer Typ: 'list'

94

Ich versuche eine Datei zu nehmen, die so aussieht

AAA x 111
AAB x 111
AAA x 112
AAC x 123
...

Und verwenden Sie ein Wörterbuch, damit die Ausgabe so aussieht

{AAA: ['111', '112'], AAB: ['111'], AAC: [123], ...}

Das habe ich versucht

file = open("filename.txt", "r") 
readline = file.readline().rstrip()
while readline!= "":
    list = []
    list = readline.split(" ")
    j = list.index("x")
    k = list[0:j]
    v = list[j + 1:]
    d = {}
    if k not in d == False:
        d[k] = []
    d[k].append(v)
    readline = file.readline().rstrip()

Ich bekomme immer eine TypeError: unhashable type: 'list'. Ich weiß, dass Schlüssel in einem Wörterbuch keine Listen sein können, aber ich versuche, meinen Wert in eine Liste zu verwandeln, die nicht der Schlüssel ist. Ich frage mich, ob ich irgendwo einen Fehler gemacht habe.

Keenan
quelle

Antworten:

56

Wie aus den anderen Antworten hervorgeht, liegt der Fehler daran k = list[0:j], dass Ihr Schlüssel in eine Liste konvertiert wird. Eine Sache, die Sie versuchen könnten, ist die Überarbeitung Ihres Codes, um die splitFunktion zu nutzen:

# Using with ensures that the file is properly closed when you're done
with open('filename.txt', 'rb') as f:
  d = {}
  # Here we use readlines() to split the file into a list where each element is a line
  for line in f.readlines():
    # Now we split the file on `x`, since the part before the x will be
    # the key and the part after the value
    line = line.split('x')
    # Take the line parts and strip out the spaces, assigning them to the variables
    # Once you get a bit more comfortable, this works as well:
    # key, value = [x.strip() for x in line] 
    key = line[0].strip()
    value = line[1].strip()
    # Now we check if the dictionary contains the key; if so, append the new value,
    # and if not, make a new list that contains the current value
    # (For future reference, this is a great place for a defaultdict :)
    if key in d:
      d[key].append(value)
    else:
      d[key] = [value]

print d
# {'AAA': ['111', '112'], 'AAC': ['123'], 'AAB': ['111']}

Beachten Sie, dass Sie bei Verwendung von Python 3.x eine geringfügige Anpassung vornehmen müssen, damit es ordnungsgemäß funktioniert. Wenn Sie die Datei mit öffnen rb, müssen Sie verwenden line = line.split(b'x')(wodurch sichergestellt wird, dass Sie das Byte mit dem richtigen Typ von Zeichenfolge teilen). Sie können die Datei auch mit with open('filename.txt', 'rU') as f:(oder sogar with open('filename.txt', 'r') as f:) öffnen und sie sollte einwandfrei funktionieren.

RocketDonkey
quelle
Ich habe es versucht und erhalte TypeError: Typ str unterstützt die Puffer-API in der Zeile "line = line.split ('x')" nicht
Keenan
1
@ user1871081 Ah, verwenden Sie Python 3.x? Ich werde ein Update veröffentlichen, das damit funktionieren sollte.
RocketDonkey
31

Hinweis: Diese Antwort beantwortet die gestellte Frage nicht explizit. Die anderen Antworten machen es. Da die Frage für ein Szenario spezifisch ist und die angesprochene Ausnahme allgemein ist , verweist diese Antwort auf den allgemeinen Fall.

Hash-Werte sind nur Ganzzahlen, mit denen Wörterbuchschlüssel während einer Wörterbuchsuche schnell verglichen werden.

Intern hash()ruft method die __hash__()Methode eines Objekts auf, die standardmäßig für jedes Objekt festgelegt ist.

Konvertieren einer verschachtelten Liste in eine Gruppe

>>> a = [1,2,3,4,[5,6,7],8,9]
>>> set(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

Dies geschieht aufgrund der Liste in einer Liste, die nicht gehasht werden kann. Was durch Konvertieren der internen verschachtelten Listen in ein Tupel gelöst werden kann ,

>>> set([1, 2, 3, 4, (5, 6, 7), 8, 9])
set([1, 2, 3, 4, 8, 9, (5, 6, 7)])

Explizites Hashing einer verschachtelten Liste

>>> hash([1, 2, 3, [4, 5,], 6, 7])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'


>>> hash(tuple([1, 2, 3, [4, 5,], 6, 7]))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

>>> hash(tuple([1, 2, 3, tuple([4, 5,]), 6, 7]))
-7943504827826258506

Die Lösung, um diesen Fehler zu vermeiden, besteht darin, die Liste so umzustrukturieren, dass verschachtelte Tupel anstelle von Listen vorhanden sind.

Alles ist gut
quelle
4
Was ist, wenn die Liste zu groß ist? sieht aus, das ist eine gute Lösung, aber nicht allgemein genug
msh855
1
@ msh855 gibt es eine Größenbeschränkung? Ich habe das Wörterbuch mit einem Tupel der Größe 100.000 getestet und es hat gut funktioniert (ich verwende Python 3.6)
Sreram
18

Sie versuchen, k(was eine Liste ist) als Schlüssel für zu verwendend . Listen sind veränderbar und können nicht als Diktatschlüssel verwendet werden.

Außerdem initialisieren Sie die Listen im Wörterbuch aufgrund dieser Zeile nie:

if k not in d == False:

Welches sollte sein:

if k not in d == True:

Welches sollte eigentlich sein:

if k not in d:
Jesse das Spiel
quelle
5

Der Grund, warum Sie die unhashable type: 'list'Ausnahme erhalten, ist, dass k = list[0:j]Sets kein "Slice" der Liste sind, was logischerweise eine andere, oft kürzere Liste ist. Was Sie brauchen, ist, nur das erste Element in der Liste zu erhalten, das so geschrieben ist k = list[0]. Das gleiche v = list[j + 1:]sollte nur v = list[2]für das dritte Element der Liste gelten, das vom Aufruf an zurückgegeben wurde readline.split(" ").

Ich habe einige andere wahrscheinliche Probleme mit dem Code bemerkt, von denen ich einige erwähnen werde. Ein großer Punkt ist, dass Sie nicht (neu) initialisieren möchtend mit d = {}für jede Zeile in der Schleife zu lesen. Ein weiterer Grund ist, dass es im Allgemeinen keine gute Idee ist, Variablen wie die integrierten Typen zu benennen, da Sie dadurch nicht auf einen von ihnen zugreifen können, wenn Sie ihn benötigen - und es ist verwirrend für andere, die an den gewöhnt sind Namen, die einen dieser Standardartikel bezeichnen. Aus diesem Grund sollten Sie Ihre Variablenvariable listanders umbenennen , um solche Probleme zu vermeiden.

Hier ist eine funktionierende Version von Ihnen mit diesen Änderungen. Ich habe auch den ifAnweisungsausdruck vereinfacht , mit dem überprüft wird, ob der Schlüssel bereits im Wörterbuch enthalten ist. Es gibt noch kürzere implizite Möglichkeiten, dies zu tun, jedoch unter Verwendung einer Bedingung Aussage ist vorerst in Ordnung.

d = {}
file = open("filename.txt", "r")
readline = file.readline().rstrip()
while readline:
    lst = readline.split(" ") # Split into sequence like ['AAA', 'x', '111'].
    k = lst[0]  # First item.
    v = lst[2]  # Third item.
    if k not in d:  # New key?
        d[k] = []  # Initialize its associated value to an empty list.
    d[k].append(v)
    readline = file.readline().rstrip()

file.close()  # Done reading file.
print('d: {}'.format(d))

Ausgabe:

d: {'AAA': ['111', '112'], 'AAC': ['123'], 'AAB': ['111']}
Martineau
quelle
0

Das TypeErrorpassiert, weil kes sich um eine Liste handelt, da sie mit einem Slice aus einer anderen Liste mit der Zeile erstellt wird k = list[0:j]. Dies sollte wahrscheinlich so etwas seink = ' '.join(list[0:j]) , also haben Sie stattdessen eine Zeichenfolge.

Darüber hinaus ist Ihre ifAussage falsch, wie in Jesses Antwort vermerkt, die lauten sollte if k not in doderif not k in d (ich bevorzuge letzteres).

Sie löschen auch Ihr Wörterbuch bei jeder Iteration, da Sie sich d = {}in Ihrer forSchleife befinden.

Beachten Sie, dass Sie auch keine listoder fileals Variablennamen verwenden sollten, da Sie integrierte Funktionen maskieren.

So würde ich Ihren Code umschreiben:

d = {}
with open("filename.txt", "r") as input_file:
    for line in input_file:
        fields = line.split()
        j = fields.index("x")
        k = " ".join(fields[:j])
        d.setdefault(k, []).append(" ".join(fields[j+1:]))

Die dict.setdefault()obige Methode ersetzt die if k not in dLogik aus Ihrem Code.

Andrew Clark
quelle
Während Präferenz Ihr volles Recht ist, not k in dkönnte ein Anfänger verwirren (not k) in d, während, während k not in dkeine Mehrdeutigkeit hat
Jesse das Spiel
Ich würde sogar argumentieren, dass es der "pythonische" Weg not inist, wie er als Operator aufgeführt ist .
Jesse das Spiel
Ja, ich denke, meine Präferenz liegt wahrscheinlich darin, zuerst andere Sprachen zu lernen, wo Sie für so etwas wie einen Eindämmungstest keine Operatoren dafür hätten, also würden Sie so etwas tun !a.contains(b). not inmag pythonischer sein, ich finde das Konzept von zwei Wortoperatoren nur verwirrender als die Verwendung einer Umkehrung eines booleschen Ausdrucks.
Andrew Clark
-1
    python 3.2

    with open("d://test.txt") as f:
              k=(((i.split("\n"))[0].rstrip()).split() for i in f.readlines())
              d={}
              for i,_,v in k:
                      d.setdefault(i,[]).append(v)
Raton
quelle