Đối tượng TypeError: 'dict_keys' không hỗ trợ lập chỉ mục


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]

Khi tôi chạy shufflechức năng, nó sẽ phát sinh lỗi sau, tại sao vậy?

TypeError: 'dict_keys' object does not support indexing

7
dường như là một lỗi
python3

Câu trả lời:


231

Rõ ràng bạn đang chuyển vào chức năng d.keys()của bạn shuffle. Có lẽ điều này đã được viết bằng python2.x (khi d.keys()trả về một danh sách). Với python3.x, d.keys()trả về một dict_keysđối tượng hoạt động giống như a sethơn là a list. Như vậy, nó không thể được lập chỉ mục.

Giải pháp là vượt qua list(d.keys())(hoặc đơn giản list(d)) để shuffle.


22
. . . Hoặc chỉ list(d)cung cấp cho bạn một danh sách các khóa trên cả python2.x và python3.x mà không tạo bất kỳ bản sao nào :-)
mgilson

11
Đây là một quyết định thay đổi thiết kế phá vỡ kỳ lạ cho python3.
Jason

9
Bạn có thể nghĩ như vậy, nhưng tôi chắc chắn nghĩ rằng đó là quyết định chính xác. Đối dict_keystượng hành xử rất giống như chỉ là một nửa các phím. Cụ thể, họ hỗ trợ thử nghiệm thành viên O (1) (và các phương pháp giống như tập hợp khác có thể được triển khai hiệu quả trên thực tế đó). Những điều này không thể có với một danh sách và nếu bạn muốn có một danh sách các khóa của chính tả, bạn luôn có thể làm một cách đơn giản list(your_dictionary)để có được nó.
mgilson

Điều này hữu ích cho tôi khi thấy python3 yêu cầu chúng tôi bọc từ điển với danh sách.
DataEngineer

2
@Crt - shufflelà tên của hàm trong mã của người gửi ban đầu (hàm đang gây ra lỗi). Nhìn vào mã, tôi nghĩ rằng nó đã được sao chép / dán từ random.shuffletriển khai trong thư viện chuẩn :-)
mgilson

11

Bạn đang chuyển kết quả của somedict.keys()hàm. Trong Python 3, dict.keyskhông trả về danh sách, nhưng một đối tượng giống như tập hợp thể hiện chế độ xem các khóa của từ điển và (giống như tập hợp) không hỗ trợ lập chỉ mục.

Để khắc phục sự cố, sử dụng list(somedict.keys())để thu thập các phím và làm việc với điều đó.


10

Chuyển đổi một lần lặp thành một danh sách có thể có một chi phí. Thay vào đó, để có được mục đầu tiên, bạn có thể sử dụng:

next(iter(keys))

Hoặc, nếu bạn muốn lặp lại tất cả các mục, bạn có thể sử dụng:

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

1

Tại sao bạn cần thực hiện shuffle khi nó đã tồn tại? Ở trên vai người khổng lồ.

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)

Câu trả lời là kiến ​​thức chung có liên quan, nhưng nó không giải quyết được những gì OP đang hỏi.
JC Rocnhoe

Bạn đúng. Có vẻ như anh ấy muốn thực hiện ngẫu nhiên của riêng mình.
FooBar167

1
psah, có lẽ anh ta thực sự không biết rằng anh ta có thể sử dụng tích hợp sẵn, nhưng câu hỏi thực sự có vẻ là về lỗi loại. Tuy nhiên, tôi hy vọng anh ấy đã chuyển đổi và sử dụng tùy chọn của bạn (trừ khi đó là một điều gì đó rất cụ thể) để tuân theo các nguyên tắc cơ bản về DRY và kinh tế mã.
JC Rocnhoe

1

Trong Python 2 dict.keys () trả về một danh sách, trong khi trong Python 3, nó trả về một trình tạo.

Bạn chỉ có thể lặp lại các giá trị của nó nếu không bạn có thể phải chuyển đổi nó thành một danh sách tức là chuyển nó sang một hàm danh sách.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.