TypeError: unhashable type: 'list' nasıl aşılır


98

Şuna benzeyen bir dosya almaya çalışıyorum:

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

Ve çıktının böyle görünmesi için bir sözlük kullanın

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

Bu denediğim şey

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()

Bir TypeError: unhashable type: 'list'. Bir sözlükteki anahtarların liste olamayacağını biliyorum ama değerimi anahtar değil liste haline getirmeye çalışıyorum. Bir yerde bir hata yapıp yapmadığımı merak ediyorum.

Yanıtlar:


58

Diğer cevapların da gösterdiği gibi, hata k = list[0:j]anahtarınızın bir listeye dönüştürülmesinden kaynaklanmaktadır. Deneyebileceğiniz bir şey, splitişlevden yararlanmak için kodunuzu yeniden çalışmaktır :

# 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']}

Python 3.x kullanıyorsanız, düzgün çalışması için küçük bir ayarlama yapmanız gerekeceğini unutmayın. Dosyayı ile açarsanız, rbkullanmanız gerekir line = line.split(b'x')(bu, baytı uygun tipte dizeyle bölmenizi sağlar). Dosyayı with open('filename.txt', 'rU') as f:(veya hatta with open('filename.txt', 'r') as f:) kullanarak da açabilirsiniz ve iyi çalışması gerekir.


36

Not: Bu cevap, sorulan soruya açıkça cevap vermemektedir. diğer cevaplar yapıyor. Soru bir senaryoya özgü olduğundan ve ortaya çıkan istisna genel olduğundan , Bu cevap genel duruma işaret etmektedir.

Karma değerler, sözlük araması sırasında sözlük anahtarlarını hızlı bir şekilde karşılaştırmak için kullanılan tam sayılardır.

Dahili olarak, hash()yöntem __hash__()herhangi bir nesne için varsayılan olarak ayarlanan bir nesnenin yöntemini çağırır .

İç içe geçmiş bir listeyi bir kümeye dönüştürme

>>> 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'

Bu, hashing uygulanamayan bir liste olan bir liste içindeki liste nedeniyle olur. İç içe geçmiş listeleri bir demete dönüştürerek çözülebilir ,

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

İç içe geçmiş bir listeyi açıkça karma oluşturma

>>> 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

Bu hatayı önlemenin çözümü, listeyi listeler yerine iç içe geçmiş demetler içerecek şekilde yeniden yapılandırmaktır.


4
ya liste çok büyükse ?? iyi bir çözüm gibi görünüyor, ancak yeterince genel değil
msh855

1
@ msh855 herhangi bir boyut sınırı var mı? Sözlüğü 100.000 büyüklüğünde bir tuple ile test ettim ve benim için iyi çalıştı (python 3.6 kullanıyorum)
Sreram

@ msh855 Bu, bu sorunu kurtulmak için tek yoldur SİZE CAN DEĞİL HASH liste halinde PYTHON, NE OLURSA OLSUN , liste oluşturarak zaman daha iç içe bir liste ya da başlık olur eğer önemli değil, değişkenlikle tüm konular ve işlemler genellikle O (1) 'dir, bu nedenle genellikle oluşturulurken listenin boyutu önemli değildir. DEĞİLSE , bir liste üzerinde çalışırken bir TypeError istisnasını yakalamayı deneyebilirsiniz , kolay GENEL yol!
Hepsi Іѕ Vаиітy

21

kAnahtar olarak (ki bu bir liste) kullanmaya çalışıyorsunuz d. Listeler değiştirilebilir ve dikte anahtarları olarak kullanılamaz.

Ayrıca, bu satırdan dolayı sözlükteki listeleri asla başlatmıyorsunuz:

if k not in d == False:

Hangisi olmalı:

if k not in d == True:

Hangisi aslında şöyle olmalıdır:

if k not in d:

6

İstisnayı almanızın nedeni unhashable type: 'list', k = list[0:j]kümelerin kmantıksal olarak başka, genellikle daha kısa olan listenin bir "dilimi" olması. İhtiyacınız olan şey, listedeki ilk öğeyi böyle yazarak almaktır k = list[0]. Aynı v = list[j + 1:]şey v = list[2], çağrıdan döndürülen listenin üçüncü öğesi için de olmalıdır readline.split(" ").

Kodla ilgili birkaç olası sorun olduğunu fark ettim, bunlardan birkaçından bahsedeceğim. Hem de büyük bir sen (yeniden) istiyoruz başlatmak kalmamasıdır dile d = {}her satır döngü içinde okumak için. Diğeri ise, değişkenleri yerleşik türlerden herhangi biriyle aynı şekilde adlandırmanın genellikle iyi bir fikir olmamasıdır çünkü bu, ihtiyaç duyduğunuzda bunlardan birine erişmenizi engelleyecektir - ve buna alışkın olanlar için kafa karıştırıcıdır. bu standart öğelerden birini belirten isimler. Bu nedenle, böyle listsorunlardan kaçınmak için değişken değişkeninizi farklı bir şekilde yeniden adlandırmalısınız .

İşte bu değişikliklerle birlikte çalışan bir versiyonunuz, ayrıca ifanahtarın zaten sözlükte olup olmadığını kontrol etmek için kullandığınız ifade ifadesini de değiştirdim ve şimdi setdefault()aynı şeyi biraz daha kısa bir şekilde gerçekleştirmek için bir sözlüğün yöntemini kullanıyorum.

d = {}
with open("nameerror.txt", "r") as file:
    line = file.readline().rstrip()
    while line:
        lst = line.split() # Split into sequence like ['AAA', 'x', '111'].
        k, _, v = lst[:3]  # Get first and third items.
        d.setdefault(k, []).append(v)
        line = file.readline().rstrip()

print('d: {}'.format(d))

Çıktı:

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

0

TypeErrorÇünkü ne olup kbu çizgi ile başka listeden bir dilim kullanılarak oluşturulan olduğundan, bir listedir k = list[0:j]. Bu muhtemelen şöyle bir şey olmalı k = ' '.join(list[0:j]), onun yerine bir dizeniz var.

Buna ek olarak, ifJesse cevap, okumalısınız tarafından belirtildiği gibi ifade hatalıdır if k not in dveya if not k in d(Ben ikinci tercih).

Döngünüzün d = {}içine girdiğiniz için her yinelemede sözlüğünüzü de temizliyorsunuz for.

Yerleşikleri maskeleyeceğiniz için değişken isimleri olarak listveya kullanmamalısınız file.

İşte kodunuzu nasıl yeniden yazacağım:

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:]))

Yukarıdaki dict.setdefault()yöntem if k not in d, kodunuzdaki mantığı değiştirir .


tercihinin tam doğru iken, not k in dbir acemi karmaşık hale getirebileceğini (not k) in dederken, k not in dhiçbir belirsizliğe sahiptir
Jesse Oyun

Operatörnot in olarak listelendiği şekliyle bunun 'pitonik' yol olduğunu bile iddia edebilirim .
Jesse the Game

Evet, sanırım tercihim muhtemelen önce diğer dilleri öğrenmekten geliyor, burada kontrol testi gibi bir şey için bunun için operatörlere sahip olmayacaksın, bu yüzden böyle bir şey yapardın !a.contains(b). not indaha pitonik olabilir, sadece iki kelime operatörü kavramını bir boole ifadesinin tersini kullanmaktan daha kafa karıştırıcı buluyorum.
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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.