TypeError: objek 'dict_keys' tidak mendukung pengindeksan

144
def shuffle(self, x, random=None, int=int):
    """x, random=random.random -> shuffle list x in place; return None.

    Optional arg random is a 0-argument function returning a random
    float in [0.0, 1.0); by default, the standard random.random.
    """

    randbelow = self._randbelow
    for i in reversed(range(1, len(x))):
        # pick an element in x[:i+1] with which to exchange x[i]
        j = randbelow(i+1) if random is None else int(random() * (i+1))
        x[i], x[j] = x[j], x[i]

Ketika saya menjalankan shufflefungsi itu menimbulkan kesalahan berikut, mengapa begitu?

TypeError: 'dict_keys' object does not support indexing
gate_007
sumber
7
tampaknya menjadi kesalahan
python3

Jawaban:

231

Jelas Anda melewati fungsi d.keys()Anda shuffle. Mungkin ini ditulis dengan python2.x (ketika d.keys()mengembalikan daftar). Dengan python3.x, d.keys()mengembalikan dict_keysobjek yang berperilaku lebih seperti seta list. Karena itu, tidak dapat diindeks.

Solusinya adalah lulus list(d.keys())(atau hanya list(d)) ke shuffle.

mgilson
sumber
22
. . . Atau list(d)yang akan memberi Anda daftar kunci pada python2.x dan python3.x tanpa membuat salinan :-)
mgilson
11
Ini adalah keputusan perubahan desain aneh yang aneh untuk python3.
Jason
9
Anda mungkin berpikir begitu, tetapi saya pasti berpikir bahwa itu adalah keputusan yang tepat. The dict_keysobjek berperilaku lebih banyak seperti hanya tombol setengah dari dict. Secara khusus, mereka mendukung O (1) pengujian keanggotaan (dan metode set-seperti lainnya yang dapat diimplementasikan secara efisien di atas fakta itu). Hal-hal ini tidak mungkin dilakukan dengan daftar dan jika Anda menginginkan daftar kunci dikt, Anda selalu dapat melakukannya list(your_dictionary)untuk mendapatkannya.
mgilson
ini membantu saya untuk melihat bahwa python3 mengharuskan kita untuk membungkus kamus dengan daftar.
DataEngineer
2
@Crt - shuffleadalah nama fungsi dalam kode poster asli (fungsi yang melempar kesalahan). Melihat kode tersebut, saya pikir kode itu disalin / ditempelkan dari random.shuffleimplementasi di perpustakaan standar :-)
mgilson
11

Anda melewatkan hasil somedict.keys()ke fungsi. Dalam Python 3, dict.keystidak mengembalikan daftar, tetapi objek set-seperti yang mewakili tampilan kunci kamus dan (sedang set-seperti) tidak mendukung pengindeksan.

Untuk memperbaiki masalah, gunakan list(somedict.keys())untuk mengumpulkan kunci, dan bekerja dengan itu.

pengguna4815162342
sumber
10

Mengubah iterable ke daftar mungkin memiliki biaya. Sebagai gantinya, untuk mendapatkan item pertama, Anda dapat menggunakan:

next(iter(keys))

Atau, jika Anda ingin mengulang semua item, Anda dapat menggunakan:

items = iter(keys)
while True:
    try:
        item = next(items)
    except StopIteration as e:
        pass # finish
sahama
sumber
1

Mengapa Anda perlu menerapkan shuffle ketika sudah ada? Tetap di pundak raksasa.

import random

d1 = {0:'zero', 1:'one', 2:'two', 3:'three', 4:'four',
     5:'five', 6:'six', 7:'seven', 8:'eight', 9:'nine'}

keys = list(d1)
random.shuffle(keys)

d2 = {}
for key in keys: d2[key] = d1[key]

print(d1)
print(d2)
FooBar167
sumber
Jawabannya adalah pengetahuan umum yang relevan, tetapi tidak membahas apa yang diminta OP.
JC Rocamonde
Kamu benar. Tampaknya dia ingin menerapkan pengacak sendiri.
FooBar167
1
psah, mungkin dia tidak benar-benar tahu bahwa dia bisa menggunakan built-in, tetapi pertanyaannya sebenarnya adalah tentang kesalahan ketik. Tetap saja, saya harap dia beralih dan menggunakan opsi Anda (kecuali itu sesuatu yang sangat spesifik) untuk mengikuti prinsip KERING dan prinsip ekonomi-kode.
JC Rocamonde
1

Dalam Python 2 dict.keys () mengembalikan daftar, sedangkan di Python 3 mengembalikan generator.

Anda hanya bisa mengulangi nilai-nilai itu lain jika Anda mungkin harus secara eksplisit mengubahnya menjadi daftar yaitu meneruskannya ke fungsi daftar.

DeWil
sumber