Python xông mở rộng cho một từ điển


463

Đó là cách tốt nhất để mở rộng một từ điển với một từ điển khác? Ví dụ:

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

Tôi đang tìm kiếm bất kỳ hoạt động để có được forvòng lặp tránh này :

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

Tôi muốn làm một cái gì đó như:

a.extend(b)  # This does not work

25
Tôi biết danh sách [], sau đó tôi cho rằng có thể là công việc cho người khác, không phải là tuyệt vời ;-)
FerranB

Câu trả lời:


695

6
Sau khi đọc tài liệu người ta sẽ hiểu tại sao lại có một ´upupate, nhưng không có extextend.
georg

58
Hãy nhớ rằng update () trực tiếp sửa đổi dict và trả về Không.
e18r

5
Nhưng nếu bạn chỉ muốn mở rộng dict với các giá trị chưa được xác định (nghĩa là không ghi đè các giá trị hiện tại) thì sao? Ví dụ, cập nhật một dict {"a":2, "b":3}với dict {"b":4, "c":5}thành dict {"a":2, "b":3,"c":5}? Tất nhiên có thể sử dụng bằng update()cách di chuyển một số thứ xung quanh, nhưng sẽ tốt hơn nếu nó có thể được hoàn thành chỉ trong một dòng ...
Nearoo

17
@Nearoo - chỉ cần cập nhật theo cách ngược lại; thay vì x.update (y) [sẽ ghi đè lên các giá trị x với y], hãy sử dụng y.update (x) [ghi đè các giá trị y bằng x] và sử dụng y làm lệnh chính bạn đã chọn cho các hoạt động tiếp theo
jonathanl

Hãy nhớ rằng updateâm thầm ghi đè các mục hiện có. Tức là, bất kỳ giá trị nào bghi đè lên các khóa trong acho các khóa chồng chéo.
CGFoX

186

Một viên ngọc đẹp trong câu hỏi đóng này :

"Cách oneliner", thay đổi cả hai đầu vào, là

basket = dict(basket_one, **basket_two)

Tìm hiểu những gì **basket_two(cái **) có nghĩa là ở đây .

Trong trường hợp có xung đột, các mục từ basket_twosẽ ghi đè lên các mục từ basket_one. Khi một người đi, điều này khá dễ đọc và minh bạch, và tôi không bị buộc phải sử dụng nó bất cứ khi nào một lệnh kết hợp hai điều khác trở nên hữu ích (bất kỳ độc giả nào gặp khó khăn trong việc hiểu nó thực tế sẽ được phục vụ rất tốt bởi cách thức này thúc đẩy anh ấy hoặc cô ấy hướng tới việc tìm hiểu dict**hình thức ;-). Vì vậy, ví dụ, sử dụng như:

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

là sự xuất hiện hợp lý thường xuyên trong mã của tôi.

Ban đầu được gửi bởi Alex Martelli

Lưu ý: Trong Python 3, điều này sẽ chỉ hoạt động nếu mọi khóa trong rổ_two là a string.


3
Tài liệu cho dictdễ tìm trong khi **khó hơn một chút (từ khóa là kwargs ). Đây là một lời giải thích hay: saltycrane.com/blog/2008/01/ Cách
johndodo

4
điều này có thể được sử dụng để tạo một biến thứ hai với một lệnh duy nhất, trong khi basket_one.update(<dict>)như tên đã nói, cập nhật một từ điển hiện có (hoặc một từ được nhân bản).
furins

2
Lưu ý rằng trong Python 3, tên đối số và do đó, các khóa của **anotherdict, phải là chuỗi.
Petr Viktorin

Cảm ơn @johndodo - Tôi đã tích hợp các đề xuất của bạn vào bài viết.
Tom Leys

1
Một thay thế chức năng tốt đẹp cho câu trả lời được chấp nhận. Cách tiếp cận này là mong muốn nếu bạn cần sử dụng trực tiếp dict mới kết hợp. (cũng xem bình luận của @ e18r về câu trả lời được chấp nhận).
chinnychinchin

45

Bạn đã thử sử dụng hiểu từ điển với ánh xạ từ điển:

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

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

Một cách khác là sử dụng dict (iterable, ** kwarg)

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

Trong Python 3.9, bạn có thể thêm hai dict bằng union | nhà điều hành

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

5
FYI: đây không phải là một cú pháp hợp lệ trong Python 2.7
Asav Patel

2
Cú pháp này khá mới (Python 3.5)
pianoJames

24
a.update(b)

Sẽ thêm khóa và giá trị từ b đến a , ghi đè nếu đã có giá trị cho khóa.


17

Như những người khác đã đề cập, a.update(b)đối với một số ý kiến absẽ đạt được kết quả mà bạn đã yêu cầu trong câu hỏi của mình. Tuy nhiên, tôi muốn chỉ ra rằng nhiều lần tôi đã thấy extendphương pháp ánh xạ / thiết lập các đối tượng mong muốn rằng trong cú pháp a.extend(b), acác giá trị của KHÔNG nên được ghi đè bằng bcác giá trị. a.update(b)ghi đè lên acác giá trị của nó, và do đó không phải là một lựa chọn tốt cho extend.

Lưu ý rằng một số ngôn ngữ gọi phương thức này defaultshoặc inject, vì nó có thể được coi là một cách để tiêm các giá trị b (có thể là một tập hợp các giá trị mặc định) vào từ điển mà không ghi đè các giá trị có thể tồn tại.

Tất nhiên, bạn có thể lưu ý đơn giản a.extend(b)gần giống như b.update(a); a=b. Để xóa bài tập, bạn có thể làm như vậy:

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)

Cảm ơn Tom Leys vì ý tưởng thông minh đó bằng cách sử dụng hàm tạo không có tác dụng phụ dictcho extend.


1

Bạn cũng có thể sử dụng bộ sưu tập của python.Chainmap được giới thiệu trong python 3.3.

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

Điều này có một vài lợi thế có thể, tùy thuộc vào trường hợp sử dụng của bạn. Chúng được giải thích chi tiết hơn ở đây , nhưng tôi sẽ cung cấp một cái nhìn tổng quan ngắn gọn:

  • Một sơ đồ chuỗi chỉ sử dụng các khung nhìn của từ điển, vì vậy không có dữ liệu nào thực sự được sao chép. Điều này dẫn đến việc xâu chuỗi nhanh hơn (nhưng tra cứu chậm hơn)
  • Không có khóa nào thực sự được ghi đè, vì vậy, nếu cần, bạn biết liệu dữ liệu đến từ a hoặc b.

Điều này chủ yếu làm cho nó hữu ích cho những thứ như từ điển cấu hình.


0

Trong trường hợp bạn cần nó dưới dạng Class , bạn có thể mở rộng nó bằng dict và sử dụng phương thức cập nhật :

Class a(dict):
  # some stuff
  self.update(b)
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.