ฉันจะเริ่มต้นพจนานุกรมของรายการว่างใน Python ได้อย่างไร


89

ความพยายามของฉันในการสร้างพจนานุกรมรายการโดยใช้โปรแกรมไม่สามารถอนุญาตให้ฉันกำหนดคีย์พจนานุกรมทีละรายการได้ เมื่อใดก็ตามที่ฉันสร้างพจนานุกรมของรายการและพยายามผนวกเข้ากับคีย์เดียวรายการทั้งหมดจะได้รับการอัปเดต นี่เป็นกรณีทดสอบที่ง่ายมาก:

data = {}
data = data.fromkeys(range(2),[])
data[1].append('hello')
print data

ผลลัพธ์ที่แท้จริง: {0: ['hello'], 1: ['hello']}

ผลลัพธ์ที่คาดหวัง: {0: [], 1: ['hello']}

นี่คือสิ่งที่ได้ผล

data = {0:[],1:[]}
data[1].append('hello')
print data

ผลลัพธ์ที่เกิดขึ้นจริงและที่คาดหวัง: {0: [], 1: ['hello']}

เหตุใดfromkeysวิธีนี้จึงไม่ได้ผลตามที่คาดไว้

คำตอบ:


112

การส่งผ่าน[]อาร์กิวเมนต์ที่สองเพื่อdict.fromkeys()ให้ได้ผลลัพธ์ที่ค่อนข้างไร้ประโยชน์ - ค่าทั้งหมดในพจนานุกรมจะเป็นรายการเดียวกัน

ใน Python 2.7 ขึ้นไปคุณสามารถใช้ความเข้าใจแบบแยกส่วนแทนได้:

data = {k: [] for k in range(2)}

ใน Python เวอร์ชันก่อนหน้าคุณสามารถใช้ไฟล์

data = dict((k, []) for k in range(2))

3
นี่เป็นพฤติกรรมที่ไม่ใช้งานง่ายมีความคิดว่าทำไมจึงใช้วัตถุเดียวกันสำหรับคีย์ทั้งหมด?
บาร์

3
@ บาร์เนื่องจากไม่มีสิ่งอื่นใดที่ฟังก์ชันสามารถทำได้ภายในความหมายของภาษา Python คุณส่งผ่านออบเจ็กต์เดียวเพื่อใช้เป็นค่าสำหรับคีย์ทั้งหมดดังนั้นอ็อบเจ็กต์เดียวจะถูกใช้สำหรับคีย์ทั้งหมด มันจะดีกว่าสำหรับfromkeys()วิธีการที่จะยอมรับการทำงานของโรงงานแทนเพื่อให้เราสามารถผ่านในlistขณะที่ฟังก์ชั่นและ funciton ว่าจะเรียกว่าครั้งเดียวสำหรับแต่ละคีย์ที่สร้างขึ้น dict.fromkeys()แต่ที่ไม่ได้เกิดขึ้นจริงของ
Sven Marnach

3
สิ่งนี้ไม่ง่ายเลย ฉันใช้เวลาหนึ่งชั่วโมงในการค้นหา ขอบคุณ
Astrid

1
สิ่งเดียวกันจะเกิดขึ้นถ้าคุณส่งคำสั่ง () เป็นอาร์กิวเมนต์ที่สอง พฤติกรรมที่ทำให้งงงวยมาก
ออร์ลี่

@Orly นี่เป็นเพราะพจนานุกรมว่างรายการแรกถูกสร้างขึ้นจากนั้นการอ้างอิงถึงมันจะถูกส่งไปยังการเริ่มต้นทั้งหมด
Dr_Zaszuś

83

ใช้defaultdictแทน:

from collections import defaultdict
data = defaultdict(list)
data[1].append('hello')

วิธีนี้ทำให้คุณไม่ต้องเริ่มต้นคีย์ทั้งหมดที่คุณต้องการใช้ในรายการล่วงหน้า

สิ่งที่เกิดขึ้นในตัวอย่างของคุณคือคุณใช้รายการหนึ่ง (ไม่แน่นอน):

alist = [1]
data = dict.fromkeys(range(2), alist)
alist.append(2)
print data

{0: [1, 2], 1: [1, 2]}เอาท์พุทหากว่า


2
ในกรณีของฉันฉันต้องเริ่มต้นคีย์ทั้งหมดก่อนเพื่อให้ตรรกะของโปรแกรมที่เหลือสามารถทำงานได้ตามที่คาดไว้ แต่นี่จะเป็นทางออกที่ดี ขอบคุณ.
Martin Burch

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

8

คุณกำลังเติมพจนานุกรมของคุณด้วยการอ้างอิงไปยังรายการเดียวดังนั้นเมื่อคุณอัปเดตการอัปเดตจะสะท้อนให้เห็นในการอ้างอิงทั้งหมด ลองใช้พจนานุกรมเพื่อความเข้าใจแทน ดู สร้างพจนานุกรมพร้อมความเข้าใจรายการใน Python

d = {k : v for k in blah blah blah}

คำแนะนำที่ดีในการเริ่มต้นค่าพจนานุกรม ... ขอบคุณโคบี้! ฉันขยายตัวอย่างของคุณเพื่อรีเซ็ตค่าในพจนานุกรมที่มีอยู่ d. ฉันทำสิ่งนี้ดังนี้: d = {k: 0 สำหรับ k in d}
John

คืออะไรvในคำตอบนี้หรือไม่?
Dr_Zaszuś

-3

คุณสามารถใช้สิ่งนี้:

data[:1] = ['hello']

2
อาจเป็นประโยชน์สำหรับ OP ในการอธิบายว่าเหตุใดจึงได้ผล คำถามเดิมโพสต์ว่าทำไมมันไม่ได้ผลตามที่คาด
william.taylor 09

@ william.taylor.09 เห็นได้ชัดว่าทำไมถึงได้ผลใช่ไหม
Conner Dassen

OP (was) ถามว่า "เหตุใดวิธี fromkeys จึงไม่ทำงานตามที่คาดไว้"
william.taylor 09
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.