Python“ ขยาย” สำหรับพจนานุกรม


462

วิธีใดที่ดีที่สุดในการขยายพจนานุกรมด้วยพจนานุกรมอื่น ตัวอย่างเช่น

>>> a = { "a" : 1, "b" : 2 }
>>> b = { "c" : 3, "d" : 4 }
>>> a
{'a': 1, 'b': 2}
>>> b
{'c': 3, 'd': 4}

ฉันกำลังมองหาการดำเนินการใด ๆ ที่จะได้รับforห่วงหลีกเลี่ยงนี้:

{ "a" : 1, "b" : 2, "c" : 3, "d" : 4 }

ฉันต้องการทำสิ่งที่ชอบ:

a.extend(b)  # This does not work

25
ผมรู้ว่าสำหรับรายการ [] จากนั้น supose ฉันอาจจะเป็นงานสำหรับคนอื่น ๆ ไม่ได้ extrange ;-)
FerranB

คำตอบ:


694

6
หลังจากอ่านเอกสารแล้วจะเข้าใจได้ว่าทำไมมี ´อัปเดต´ แต่ไม่มี ´ต่อท้าย´
georg

58
โปรดทราบว่าการอัปเดต () จะปรับเปลี่ยน dict โดยตรงและส่งคืนไม่มี
e18r

5
แต่ถ้าคุณต้องการขยาย dict ด้วยค่าที่ไม่ได้กำหนดไว้แล้ว (เช่นไม่เขียนทับค่าที่มีอยู่) เช่นอัปเดต dict {"a":2, "b":3}ด้วย dict {"b":4, "c":5}เป็น dict {"a":2, "b":3,"c":5}ไหม แน่นอนมันเป็นไปได้ที่จะใช้update()โดยการย้ายบางสิ่งไปรอบ ๆ แต่มันจะดีกว่าถ้ามันสามารถทำได้ในบรรทัดเดียวเท่านั้น ...
Nearoo

17
@Nearoo - เพียงอัปเดตทางตรงข้าม แทน x.update (y) [ซึ่งจะเขียนทับค่า x ด้วย y], ใช้ y.update (x) [ซึ่งเขียนทับค่า y ด้วย x] และใช้ y เป็น dict ที่คุณเลือกสำหรับการดำเนินการเพิ่มเติม
jonathanl

โปรดทราบว่าupdateจะเขียนทับรายการที่มีอยู่ในใจ นั่นคือค่าใด ๆ ในการbเขียนทับค่าเหล่านั้นaสำหรับคีย์ที่ทับซ้อนกัน
CGFoX

186

อัญมณีที่สวยงามในคำถามที่ปิดนี้ :

วิธี "oneliner" ซึ่งเป็นการเปลี่ยนแปลงทั้งอินพุต dicts คือ

basket = dict(basket_one, **basket_two)

เรียนรู้สิ่งที่**basket_two(คน**) หมายถึงที่นี่

ในกรณีที่มีข้อขัดแย้งรายการจาก basket_twobasket_oneจะแทนที่คนจาก เป็นหนึ่งใน liners ไปนี้เป็นสวยอ่านและโปร่งใสและฉันไม่ได้ใช้งานได้ทุกครั้งที่ dict ที่ผสมสองคนเข้ามามีประโยชน์ วิธีนี้แจ้งให้เขาหรือเธอไปสู่การเรียนรู้เกี่ยวกับdictและ**แบบฟอร์ม ;-) ตัวอย่างเช่นใช้ like:

x = mungesomedict(dict(adict, **anotherdict))

เกิดขึ้นบ่อยครั้งในรหัสของฉัน

ส่งครั้งแรกโดยAlex Martelli

หมายเหตุ:ในหลาม 3 นี้จะทำงานหากที่สำคัญใน basket_two stringทุกคนเป็น


3
เอกสารสำหรับหาdictง่ายในขณะที่**ค่อนข้างยุ่งยากเล็กน้อย (คำหลักคือkwargs ) นี่คือคำอธิบายที่ดี: saltycrane.com/blog/2008/01/…
johndodo

4
สิ่งนี้อาจถูกใช้เพื่อสร้างตัวแปรที่สองด้วยคำสั่งเดียวในขณะbasket_one.update(<dict>)ที่ชื่อกล่าวว่าปรับปรุงพจนานุกรมที่มีอยู่ (หรือโคลนหนึ่ง)
furins

2
โปรดทราบว่าใน Python 3 ชื่ออาร์กิวเมนต์และคีย์ของ**anotherdictต้องเป็นสตริง
Petr Viktorin

ขอบคุณ @johndodo - ฉันได้รวมคำแนะนำของคุณไว้ในโพสต์แล้ว
Tom Leys

1
ทางเลือกที่ใช้งานได้ดีกับคำตอบที่ยอมรับได้ วิธีนี้เป็นที่ต้องการถ้าคุณต้องการใช้ dict ที่รวมกันใหม่โดยตรง (โปรดดูความคิดเห็นของ @ e18r เกี่ยวกับคำตอบที่ยอมรับ)
chinnychinchin

45

คุณเคยลองใช้พจนานุกรมความเข้าใจกับการทำแผนที่พจนานุกรมหรือไม่:

a = {'a': 1, 'b': 2}
b = {'c': 3, 'd': 4}

c = {**a, **b}
# c = {"a": 1, "b": 2, "c": 3, "d": 4}

วิธีการทำก็คือใช้ dict (iterable, ** kwarg)

c = dict(a, **b)
# c = {'a': 1, 'b': 2, 'c': 3, 'd': 4}

ใน Python 3.9 คุณสามารถเพิ่ม dict สองอันโดยใช้ union | ผู้ประกอบการ

# use the merging operator |
c = a | b
# c = {'a': 1, 'b': 2, 'c': 3, 'd': 4}

5
FYI: นี่ไม่ใช่ไวยากรณ์ที่ถูกต้องใน Python 2.7
Asav Patel

2
รูปแบบนี้คือค่อนข้างใหม่ (Python 3.5)
pianoJames

24
a.update(b)

จะเพิ่มคีย์และค่าจากbถึงa , เขียนทับหากมีค่าสำหรับคีย์อยู่แล้ว


17

ดังที่คนอื่น ๆ ได้กล่าวเอาไว้a.update(b)สำหรับการพูดคุยaและbจะบรรลุผลตามที่คุณขอในคำถามของคุณ แต่ผมต้องการที่จะชี้ให้เห็นว่าหลายครั้งที่ฉันได้เห็นextendวิธีการของการทำแผนที่วัตถุ / ชุดปรารถนาว่าในไวยากรณ์a.extend(b), a's ค่าไม่ควรถูกเขียนทับโดยb' s ค่า a.update(b)เขียนทับa's ค่าและอื่น ๆ extendไม่ได้เป็นทางเลือกที่ดีสำหรับ

โปรดทราบว่าบางภาษาเรียกวิธีนี้defaultsหรือinjectอาจเป็นวิธีการฉีดค่าของ b (ซึ่งอาจเป็นชุดของค่าเริ่มต้น) ในพจนานุกรมโดยไม่มีการเขียนทับค่าที่อาจมีอยู่แล้ว

แน่นอนคุณสามารถทราบง่ายๆว่าเกือบจะเป็นเช่นเดียวกับa.extend(b) b.update(a); a=bหากต้องการลบการมอบหมายคุณสามารถทำได้ดังนี้:

def extend(a,b):
    """Create a new dictionary with a's properties extended by b,
    without overwriting.

    >>> extend({'a':1,'b':2},{'b':3,'c':4})
    {'a': 1, 'c': 4, 'b': 2}
    """
    return dict(b,**a)

ขอขอบคุณที่ทอมเลย์สำหรับความคิดที่ว่าสมาร์ทใช้ผลข้างเคียงน้อยกว่าคอนสตรัคสำหรับdictextend


1

นอกจากนี้คุณยังสามารถใช้คอลเลกชัน pythonChainmap ซึ่งเปิดตัวใน python 3.3

from collections import Chainmap
c = Chainmap(a, b)
c['a'] # returns 1

นี่เป็นข้อได้เปรียบที่เป็นไปได้บางประการขึ้นอยู่กับการใช้งานของคุณ มีการอธิบายรายละเอียดเพิ่มเติมที่นี่แต่ฉันจะให้ภาพรวมโดยย่อ:

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

สิ่งนี้ทำให้ส่วนใหญ่มีประโยชน์สำหรับสิ่งต่างๆเช่นพจนานุกรมกำหนดค่า


0

ในกรณีที่คุณต้องการเป็นClassคุณสามารถขยายด้วยdictและใช้วิธีการอัพเดต :

Class a(dict):
  # some stuff
  self.update(b)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.