TypeError: 'dict_keys' nesnesi indekslemeyi desteklemiyor


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]

shuffleİşlevi çalıştırdığımda aşağıdaki hatayı ortaya çıkarır, neden bu?

TypeError: 'dict_keys' object does not support indexing

7
bir python3 hatası gibi görünüyor
DataEngineer

Yanıtlar:


231

Açıkça içeri geçiyoruz d.keys()sizin için shuffleişleve. Muhtemelen bu python2.x ile yazılmıştır ( d.keys()bir liste döndürüldüğünde). Python3.x ile d.keys()bir döndüren dict_keysçok daha fazla bir nesne gibi davranır setbir daha list. Bu nedenle, endekslenemez.

Çözüm list(d.keys())(ya da basitçe list(d)) geçmektir shuffle.


22
. . . Ya da list(d)herhangi bir kopya yapmadan hem
python2.x

11
Bu python3 için garip bir kırılma değişikliği tasarım kararıdır.
Jason

9
Öyle düşünebilirsin, ama kesinlikle bunun doğru karar olduğunu düşünüyorum. dict_keysNesne çok daha fazla bir dict üstü anahtar yarısı gibi davranır. Özellikle, O (1) üyelik testini (ve bu gerçeğin üzerinde etkili bir şekilde uygulanabilecek diğer set benzeri yöntemleri) desteklerler. Bunlar bir liste ile mümkün değildir ve diktenin anahtarlarının bir listesini istiyorsanız, bunu elde etmek için her zaman yapabildiniz list(your_dictionary).
mgilson

python3'ün sözlüğü listeyle sarmamızı gerektirdiğini görmek benim için yararlı.
DataEngineer

2
@Crt - shuffleorijinal poster kodundaki işlevin adıdır (hatayı atan işlev). random.shuffle
Koduna baktığımda

11

Sonucunu somedict.keys()işleve geçiriyorsunuz . Python 3'te dict.keysbir liste döndürmez, ancak sözlüğün anahtarlarının bir görünümünü temsil eden ve (set benzeri gibi) dizine ekleme özelliğini desteklemez.

Sorunu çözmek için list(somedict.keys())tuşlarını toplamak için kullanın ve bununla çalışın.


10

Bir yinelenebilir listeye dönüştürmek bir maliyeti olabilir. Bunun yerine, ilk öğeyi almak için şunları kullanabilirsiniz:

next(iter(keys))

Veya, tüm öğeleri yinelemek istiyorsanız, şunları kullanabilirsiniz:

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

1

Neden zaten mevcutsa karıştırmayı uygulamanız gerekiyor? Devlerin omuzlarında kalın.

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)

Cevap genel bilgi ile ilgilidir, ancak OP'nin ne istediğini ele almaz.
JC Rocamonde

Haklısın. Görünüşe göre kendi randomizatörünü uygulamak istiyor.
FooBar167

1
psah, belki de yerleşik olanı kullanabileceğini bilmiyordu, ama soru aslında bir tür hata ile ilgili gibi görünüyor. Yine de, umarım temel DRY ve kod ekonomisi ilkelerini takip etmek için seçeneğinizi değiştirdi ve (çok özel bir şey olmadığı sürece) kullandı.
JC Rocamonde

1

Python 2'de dict.keys () bir liste döndürürken Python 3'te bir jeneratör döndürür.

Yalnızca değerleri üzerinden yineleyebilirsiniz, aksi takdirde bir listeye açık bir şekilde dönüştürmeniz, yani bir liste işlevine geçirmeniz gerekebilir.

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.