Làm thế nào để trả về các khóa từ điển như một danh sách trong Python?


782

Trong Python 2.7 , tôi có thể lấy các khóa , giá trị hoặc các mục từ điển dưới dạng danh sách:

>>> newdict = {1:0, 2:0, 3:0}
>>> newdict.keys()
[1, 2, 3]

Bây giờ, trong Python> = 3.3 , tôi nhận được một cái gì đó như thế này:

>>> newdict.keys()
dict_keys([1, 2, 3])

Vì vậy, tôi phải làm điều này để có được một danh sách:

newlist = list()
for i in newdict.keys():
    newlist.append(i)

Tôi đang tự hỏi, có cách nào tốt hơn để trả về một danh sách trong Python 3 không?


Vấn đề an toàn chủ đề thú vị liên quan đến chủ đề này có ở đây: blog.labix.org/2008/06/27/ trên
Paul

2
Tôi mới sử dụng Python và đối với tôi, dường như sự phổ biến của các kiểu dữ liệu mới vô dụng này là một trong những khía cạnh tồi tệ nhất của Python. Sử dụng dữ liệu dict_keys này là gì? Tại sao không phải là một danh sách?
Phil Goetz

Câu trả lời:


977

Hãy thử list(newdict.keys()).

Điều này sẽ chuyển đổi dict_keysđối tượng thành một danh sách.

Mặt khác, bạn nên tự hỏi liệu nó có quan trọng hay không. Cách mã hóa của Pythonic là giả sử gõ vịt ( nếu nó trông giống như một con vịt và nó quẫy như một con vịt, thì đó là một con vịt ). Đối dict_keystượng sẽ hành động như một danh sách cho hầu hết các mục đích. Ví dụ:

for key in newdict.keys():
  print(key)

Rõ ràng, các toán tử chèn có thể không hoạt động, nhưng điều đó không có ý nghĩa nhiều đối với một danh sách các khóa từ điển.


49
newdict.keys () không hỗ trợ lập chỉ mục
gypaetus

57
list(newdict)cũng hoạt động (ít nhất là trong python 3.4). Có bất kỳ lý do để sử dụng .keys()phương pháp?
ness101

46
Lưu ý: trong trình gỡ lỗi pdb> list(newdict.keys()) không thành công vì nó đụng độ với lệnh cùng tên của pdb. Sử dụng pdb> !list(newdict.keys())để thoát lệnh pdb.
Riaz Rizvi

24
@ naught101 Vâng, .keys()là cách rõ ràng hơn về những gì đang diễn ra.
Felix D.

2
Lưu ý rằng nếu bạn sử dụng danh sách (newdict.keys ()) rằng các khóa không theo thứ tự bạn đã đặt chúng do thứ tự băm!
Nate M

277

Python> = 3.5 thay thế: giải nén vào danh sách theo nghĩa đen [*newdict]

Các khái quát hóa giải nén mới (PEP 448) đã được giới thiệu với Python 3.5 cho phép bạn dễ dàng thực hiện:

>>> newdict = {1:0, 2:0, 3:0}
>>> [*newdict]
[1, 2, 3]

Giải nén với *các công việc với bất kỳ đối tượng nào có thể lặp lại được và do từ điển trả về các khóa của chúng khi lặp qua, bạn có thể dễ dàng tạo một danh sách bằng cách sử dụng nó trong danh sách theo nghĩa đen.

Thêm .keys()nghĩa là [*newdict.keys()]có thể giúp làm cho ý định của bạn rõ ràng hơn một chút mặc dù nó sẽ khiến bạn mất một chức năng tra cứu và gọi hàm. (trong tất cả sự trung thực, không phải là điều bạn thực sự nên lo lắng).

Các *iterablecú pháp tương tự như làm list(iterable)và hành vi của nó ban đầu được ghi nhận trong phần cuộc gọi của cuốn cẩm nang Python Reference. Với PEP 448, hạn chế về nơi *iterablecó thể xuất hiện đã được nới lỏng cho phép nó cũng được đặt trong danh sách, bộ và tuple bằng chữ, hướng dẫn tham khảo trên danh sách Biểu thức cũng được cập nhật để nêu rõ điều này.


Mặc dù tương đương list(newdict)với sự khác biệt là nó nhanh hơn (ít nhất là đối với các từ điển nhỏ) vì thực tế không có lệnh gọi hàm nào được thực hiện:

%timeit [*newdict]
1000000 loops, best of 3: 249 ns per loop

%timeit list(newdict)
1000000 loops, best of 3: 508 ns per loop

%timeit [k for k in newdict]
1000000 loops, best of 3: 574 ns per loop

với các từ điển lớn hơn, tốc độ khá giống nhau (chi phí lặp lại thông qua một bộ sưu tập lớn hơn chi phí nhỏ của một lệnh gọi hàm).


Theo cách tương tự, bạn có thể tạo bộ dữ liệu và bộ khóa từ điển:

>>> *newdict,
(1, 2, 3)
>>> {*newdict}
{1, 2, 3}

hãy cẩn thận với dấu phẩy trong trường hợp tuple!


giải thích tuyệt vời, nhưng xin vui lòng bạn có thể tham khảo bất kỳ liên kết nào mô tả loại cú pháp "* newdict" này, ý tôi là làm thế nào và tại sao điều này trả về các khóa từ từ điển chỉ để
hiểu.Thanx

1
@MYounas Cú pháp đó đã có sẵn khá lâu, ngay cả trong Python 2. Trong các lệnh gọi hàm bạn có thể thực hiện def foo(*args): print(args)theo sau foo(*{1:0, 2:0})với kết quả (1, 2)được in. Hành vi này được chỉ định trong phần Cuộc gọi của tài liệu tham khảo. Python 3.5 với PEP 448 vừa nới lỏng các hạn chế về nơi chúng có thể xuất hiện cho phép [*{1:0, 2:0}]sử dụng. Dù bằng cách nào, tôi sẽ chỉnh sửa câu trả lời của mình và bao gồm những câu hỏi này.
Dimitris Fasarakis Hilliard

1
*newdict- đây chắc chắn là câu trả lời cho những người chơi golf mã; P. Ngoài ra: trong tất cả sự trung thực, không phải là điều bạn thực sự lo lắng - và nếu bạn là, đừng sử dụng python .
Artemis vẫn không tin tưởng vào

46

list(newdict)hoạt động trong cả Python 2 và Python 3, cung cấp một danh sách đơn giản các khóa trong newdict. keys()không cần thiết (


26

Một chút tắt về định nghĩa "gõ vịt" - dict.keys()trả về một đối tượng lặp lại, không phải là một đối tượng giống như danh sách. Nó sẽ hoạt động ở bất cứ nơi nào một iterable sẽ hoạt động - không phải nơi nào cũng có một danh sách. một danh sách cũng là một lần lặp, nhưng một lần lặp lại KHÔNG phải là một danh sách (hoặc chuỗi ...)

Trong các trường hợp sử dụng thực tế, điều phổ biến nhất để làm với các phím trong một dict là lặp qua chúng, vì vậy điều này có ý nghĩa. Và nếu bạn cần chúng như một danh sách bạn có thể gọi list().

Rất giống với zip()- trong phần lớn các trường hợp, nó được lặp đi lặp lại - tại sao tạo ra một danh sách toàn bộ các bộ dữ liệu mới chỉ để lặp qua nó và sau đó ném nó đi một lần nữa?

Đây là một phần của xu hướng lớn trong python để sử dụng nhiều trình vòng lặp (và trình tạo) hơn là các bản sao của danh sách ở khắp mọi nơi.

dict.keys() Tuy nhiên, nên làm việc với sự hiểu biết - kiểm tra cẩn thận các lỗi chính tả hoặc một cái gì đó ... nó hoạt động tốt với tôi:

>>> d = dict(zip(['Sounder V Depth, F', 'Vessel Latitude, Degrees-Minutes'], [None, None]))
>>> [key.split(", ") for key in d.keys()]
[['Sounder V Depth', 'F'], ['Vessel Latitude', 'Degrees-Minutes']]

2
Bạn thậm chí không cần sử dụng .keys(); đối tượng từ điển tự lặp lại và tạo ra các khóa khi lặp lại : [key.split(", ") for key in d].
Martijn Pieters

25

Bạn cũng có thể sử dụng một danh sách hiểu :

>>> newdict = {1:0, 2:0, 3:0}
>>> [k  for  k in  newdict.keys()]
[1, 2, 3]

Hoặc, ngắn hơn,

>>> [k  for  k in  newdict]
[1, 2, 3]

Lưu ý: Đơn hàng không được đảm bảo trên các phiên bản dưới 3.7 (đơn hàng vẫn chỉ là chi tiết triển khai với CPython 3.6).


6
Chỉ cần sử dụng list(newdict). Không cần cho một sự hiểu biết danh sách ở đây.
Martijn Pieters

8

Chuyển đổi sang danh sách mà không sử dụng keysphương thức giúp dễ đọc hơn:

list(newdict)

và, khi lặp qua từ điển, không cần keys():

for key in newdict:
    print key

trừ khi bạn sửa đổi nó trong vòng lặp sẽ yêu cầu một danh sách các khóa được tạo trước:

for key in list(newdict):
    del newdict[key]

Trên Python 2 có hiệu suất tăng biên sử dụngkeys() .


8

Nếu bạn cần lưu trữ các khóa riêng biệt, đây là một giải pháp yêu cầu nhập ít hơn mọi giải pháp khác được trình bày cho đến nay, sử dụng Mở rộng Iterable Unpacking (python3.x +).

newdict = {1: 0, 2: 0, 3: 0}
*k, = newdict

k
# [1, 2, 3]

            ╒═══════════════╤═════════════════════════════════════════╕
             k = list(d)      9 characters (excluding whitespace)   
            ├───────────────┼─────────────────────────────────────────┤
             k = [*d]         6 characters                          
            ├───────────────┼─────────────────────────────────────────┤
             *k, = d          5 characters                          
            ╘═══════════════╧═════════════════════════════════════════╛

1
Nhắc nhở nhỏ duy nhất tôi chỉ ra klà luôn luôn có một danh sách ở đây. Nếu người dùng muốn một bộ hoặc đặt từ các phím họ sẽ cần quay lại các tùy chọn khác.
Dimitris Fasarakis Hilliard

1
Một lưu ý đáng chú ý hơn là, như một tuyên bố, *k, = dcó những hạn chế về nơi nó có thể xuất hiện (nhưng hãy xem và có thể cập nhật câu trả lời này cho, PEP 572 - giải nén mở rộng không được hỗ trợ cho biểu thức gán atm nhưng có thể một ngày nào đó! )
Dimitris Fasarakis Hilliard

Điều gì nếu bạn muốn cả khóa và giá trị vào danh sách?
endolith

1
@endolith có lẽ keys, vals = zip(*d.items())(mặc dù điều đó cho hai bộ dữ liệu, đủ gần). Tôi không biết về một biểu thức ngắn hơn này.
cs95

1

Tôi có thể nghĩ ra 2 cách để chúng tôi có thể trích xuất các khóa từ từ điển.

Phương pháp 1: - Để lấy các khóa bằng phương thức .keys () và sau đó chuyển đổi nó thành danh sách.

some_dict = {1: 'one', 2: 'two', 3: 'three'}
list_of_keys = list(some_dict.keys())
print(list_of_keys)
-->[1,2,3]

Phương pháp 2: - Để tạo một danh sách trống và sau đó nối các khóa vào danh sách thông qua một vòng lặp. Bạn cũng có thể nhận các giá trị với vòng lặp này (sử dụng .keys () cho chỉ các khóa và .items () cho cả khai thác khóa và giá trị)

list_of_keys = []
list_of_values = []
for key,val in some_dict.items():
    list_of_keys.append(key)
    list_of_values.append(val)

print(list_of_keys)
-->[1,2,3]

print(list_of_values)
-->['one','two','three']
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.