จะคืนค่าคีย์พจนานุกรมเป็นรายการใน Python ได้อย่างไร


779

ในPython 2.7 , ฉันจะได้รับพจนานุกรมคีย์ , ค่าหรือรายการที่เป็นรายการ:

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

ตอนนี้ในPython> = 3.3ฉันได้รับสิ่งนี้:

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

ดังนั้นฉันต้องทำสิ่งนี้เพื่อรับรายการ:

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

ฉันสงสัยว่ามีวิธีที่ดีกว่าในการส่งคืนรายการในPython 3หรือไม่?


หัวข้อความปลอดภัยที่น่าสนใจเกี่ยวกับหัวข้อนี้อยู่ที่นี่: blog.labix.org/2008/06/27/…
พอล

2
ฉันใหม่สำหรับ Python และสำหรับฉันดูเหมือนว่าการเพิ่มขึ้นของประเภทข้อมูลใหม่ที่ไร้ประโยชน์นี้เป็นหนึ่งในแง่มุมที่เลวร้ายที่สุดของ Python ประเภทข้อมูล dict_keys นี้มีประโยชน์อะไร ทำไมไม่รายการ?
Phil Goetz

คำตอบ:


975

ลองlist(newdict.keys())ดู

สิ่งนี้จะแปลงdict_keysวัตถุเป็นรายการ

ในทางกลับกันคุณควรถามตัวเองว่ามันสำคัญหรือไม่ รหัสไพ ธ อนิกคือการพิมพ์เป็ด ( ถ้ามันดูเหมือนเป็ดและมันก็เหมือนเป็ดเป็นเป็ดมันเป็นเป็ด ) dict_keysวัตถุจะทำหน้าที่เหมือนรายการเพื่อวัตถุประสงค์มากที่สุด ตัวอย่างเช่น

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

เห็นได้ชัดว่าตัวดำเนินการแทรกอาจไม่ทำงาน แต่นั่นก็ไม่สมเหตุสมผลนักสำหรับรายการของพจนานุกรมคีย์


49
newdict.keys () ไม่รองรับการจัดทำดัชนี
gypaetus

57
list(newdict)ใช้งานได้ (อย่างน้อยใน python 3.4) มีเหตุผลที่จะใช้.keys()วิธีการใด ๆ ?
naught101

46
หมายเหตุ: ในการดีบักเกอร์pdb> list(newdict.keys()) ล้มเหลวเพราะมันขัดแย้งกับคำสั่ง pdb ที่มีชื่อเดียวกัน ใช้pdb> !list(newdict.keys())เพื่อหลบหนีคำสั่ง pdb
Riaz Rizvi

23
@ naught101 ใช่.keys()เป็นวิธีที่ชัดเจนมากขึ้นในสิ่งที่เกิดขึ้น
เฟลิกซ์ดี

2
โปรดทราบว่าถ้าคุณใช้รายการ (newdict.keys ()) ว่าคีย์ไม่อยู่ในลำดับที่คุณวางไว้เนื่องจากคำสั่งแฮช!
เนท M

277

Python> = 3.5 ทางเลือก: แกะลงในรายการตามตัวอักษร [*newdict]

มีการเปิดตัวการสรุปทั่วไปใหม่(PEP 448)ด้วย Python 3.5 ที่ให้คุณทำสิ่งต่อไปนี้ได้อย่างง่ายดาย:

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

การคลายการ*ทำงานกับวัตถุใด ๆที่ทำซ้ำได้และเนื่องจากพจนานุกรมส่งคืนคีย์ของพวกเขาเมื่อทำซ้ำคุณจึงสามารถสร้างรายการได้อย่างง่ายดายโดยใช้ภายในรายการตามตัวอักษร

การเพิ่ม.keys()ie [*newdict.keys()]อาจช่วยในการทำให้เจตนาของคุณชัดเจนขึ้นแม้ว่าจะทำให้คุณต้องเสียค่าใช้จ่ายในการค้นหาและเรียกใช้ฟังก์ชัน (ซึ่งในความซื่อสัตย์สุจริตทั้งหมดคือสิ่งที่คุณไม่ควรจริงๆจะกังวลเกี่ยวกับ)

*iterableไวยากรณ์จะคล้ายกับการทำlist(iterable)และพฤติกรรมของมันถูกบันทึกครั้งแรกในส่วนการโทรของคู่มือหลามอ้างอิง ด้วย PEP 448 ข้อ จำกัด เกี่ยวกับตำแหน่งที่*iterableสามารถปรากฏได้ถูกปล่อยให้วางไว้ในรายการตั้งค่าและ tuple ตัวอักษรคู่มืออ้างอิงในรายการ Expressionได้รับการอัปเดตเพื่อระบุสิ่งนี้


แม้ว่าเทียบเท่าlist(newdict)กับความแตกต่างที่เร็วขึ้น (อย่างน้อยสำหรับพจนานุกรมขนาดเล็ก) เพราะไม่มีการเรียกใช้ฟังก์ชัน:

%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

ด้วยพจนานุกรมที่มีขนาดใหญ่กว่าความเร็วก็ค่อนข้างจะเหมือนกัน (ค่าใช้จ่ายในการวนซ้ำผ่านคอลเลกชันขนาดใหญ่ทำให้ค่าใช้จ่ายการโทรฟังก์ชั่นใหญ่)


ในทำนองเดียวกันคุณสามารถสร้างสิ่งอันดับและชุดของพจนานุกรมคีย์:

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

ระวังเครื่องหมายจุลภาคต่อท้ายในกรณี tuple!


คำอธิบายที่ดี แต่โปรดคุณสามารถอ้างอิงลิงค์ใด ๆ ที่อธิบายถึงรูปแบบของ "* newdict" นี้ฉันหมายถึงวิธีและเหตุผลที่ส่งคืนคีย์จากพจนานุกรมเพื่อความเข้าใจ
Thanx

1
@MYounas ไวยากรณ์นั้นมีอยู่บ้างในบางเวลาแม้ใน Python 2 ในการเรียกใช้ฟังก์ชันคุณสามารถทำdef foo(*args): print(args)ตามfoo(*{1:0, 2:0})ด้วยผลลัพธ์(1, 2)ที่พิมพ์ออกมา พฤติกรรมนี้มีการระบุไว้ในส่วนการโทรของคู่มืออ้างอิง Python 3.5 กับ PEP 448 เพียงแค่คลายข้อ จำกัด ที่ซึ่งสิ่งเหล่านี้สามารถปรากฏขึ้นเพื่อให้[*{1:0, 2:0}]สามารถใช้งานได้ในขณะนี้ ฉันจะแก้ไขคำตอบของฉันและรวมสิ่งเหล่านี้
Dimitris Fasarakis Hilliard

1
*newdict- นี่เป็นคำตอบที่แน่นอนสำหรับนักกอล์ฟโค้ด; นอกจากนี้: ซึ่งในความซื่อสัตย์สุจริตทุกไม่ใช่สิ่งที่คุณควรจะกังวลเกี่ยวกับ - และถ้าคุณอยู่ไม่ได้ใช้หลาม
อาร์ทิมิสยังไม่ไว้วางใจ SE

46

list(newdict)ใช้งานได้ทั้ง Python 2 และ Python 3 จัดทำรายการคีย์newdictอย่างง่าย keys()ไม่จำเป็น (:


26

ปิดบิตในคำจำกัดความ "การพิมพ์เป็ด" - dict.keys()ส่งคืนวัตถุที่ทำซ้ำได้ไม่ใช่วัตถุที่มีลักษณะเหมือนรายการ มันจะทำงานได้ทุกที่ iterable จะทำงาน - ไม่มีที่ใด ๆ ที่รายการจะ รายการนี้ยังสามารถทำซ้ำได้ แต่การทำซ้ำนั้นไม่ใช่รายการ (หรือลำดับ ...

ในกรณีการใช้งานจริงสิ่งที่พบได้บ่อยที่สุดเกี่ยวกับคีย์ใน dict คือการวนซ้ำไปมาตามลำดับดังนั้นสิ่งนี้จึงสมเหตุสมผล list()และถ้าคุณไม่ต้องการพวกเขาเป็นรายการที่คุณสามารถเรียก

คล้ายกันมากสำหรับzip()- ในกรณีส่วนใหญ่จะมีการทำซ้ำ - ทำไมจึงสร้างรายการใหม่ทั้งหมดของ tuples เพื่อย้ำผ่านมันแล้วโยนมันทิ้งอีกครั้ง?

นี่เป็นส่วนหนึ่งของเทรนด์ขนาดใหญ่ในไพ ธ อนเพื่อใช้ตัววนซ้ำ (และตัวกำเนิดไฟฟ้า) แทนที่จะทำสำเนารายการทั่วสถานที่

dict.keys() ควรทำงานร่วมกับความเข้าใจ - ตรวจสอบอย่างระมัดระวังสำหรับความผิดพลาดหรือบางสิ่งบางอย่าง ... มันทำงานได้ดีสำหรับฉัน:

>>> 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
คุณไม่จำเป็นต้องใช้งานง่ายแม้.keys(); วัตถุพจนานุกรมเป็นตัวเอง iterable [key.split(", ") for key in d]และผลิตกุญแจเมื่อซ้ำมากกว่า:
Martijn Pieters

25

คุณยังสามารถใช้list comprehension :

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

หรือสั้นกว่า

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

หมายเหตุ: การสั่งซื้อไม่ได้รับการรับรองสำหรับรุ่นที่ต่ำกว่า 3.7 (การสั่งซื้อยังเป็นเพียงรายละเอียดการใช้งานกับ CPython 3.6)


6
list(newdict)ใช้เพียงแค่ ไม่จำเป็นต้องมีรายการความเข้าใจที่นี่
Martijn Pieters

8

การแปลงเป็นรายการโดยไม่ใช้keysวิธีทำให้อ่านได้ง่ายขึ้น:

list(newdict)

และเมื่อวนลูปผ่านพจนานุกรมไม่จำเป็นต้องมีkeys():

for key in newdict:
    print key

นอกเสียจากคุณจะแก้ไขภายในลูปซึ่งจะต้องมีรายการของคีย์ที่สร้างไว้ล่วงหน้า:

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

เกี่ยวกับงูหลาม 2 keys()มีกำไรจากผลการดำเนินงานโดยใช้ร่อแร่


8

หากคุณต้องการจัดเก็บคีย์แยกกันนี่คือวิธีแก้ปัญหาที่ต้องใช้การพิมพ์น้อยกว่าโซลูชันอื่น ๆ ที่แสดงอยู่ทั้งหมดโดยใช้Extended 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
ข้อแม้เล็ก ๆ น้อย ๆ เท่านั้นที่ฉันจะชี้ให้เห็นก็kคือรายการนี้เสมอ หากผู้ใช้ต้องการ tuple หรือตั้งค่าจากปุ่มพวกเขาจะต้องถอยกลับไปที่ตัวเลือกอื่น ๆ
Dimitris Fasarakis Hilliard

1
หมายเหตุสำคัญยิ่งกว่านั้นคือข้อเท็จจริงที่ว่าคำสั่งนั้น*k, = dมีข้อ จำกัด ว่าจะปรากฏที่ใด (แต่ดูและอาจอัพเดตคำตอบนี้สำหรับPEP 572 - การขยายการขยายไม่สนับสนุนการแสดงออกที่มอบหมายใน ATM แต่อาจเป็นสักวันหนึ่ง! )
Dimitris Fasarakis Hilliard

จะทำอย่างไรถ้าคุณต้องการทั้งคีย์และค่าในรายการ
endolith

1
@endolith บางทีkeys, vals = zip(*d.items())(แม้ว่าจะให้สองสิ่งอันดับใกล้พอ) ฉันไม่รู้การแสดงออกที่สั้นกว่านี้
cs95

1

ฉันนึกถึง 2 วิธีที่เราสามารถแยกกุญแจออกจากพจนานุกรม

วิธีที่ 1: - รับคีย์โดยใช้เมธอด. key () แล้วแปลงเป็นรายการ

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

วิธีที่ 2: - เมื่อต้องการสร้างรายการที่ว่างเปล่าและจากนั้นผนวกคีย์เข้ากับรายการผ่านการวนซ้ำ คุณสามารถรับค่าด้วยลูปนี้ได้เช่นกัน (ใช้. key () สำหรับ just keys และ. items () สำหรับการแยกทั้งคีย์และค่า)

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']
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.