Cập nhật giá trị của một từ điển lồng nhau có độ sâu khác nhau


162

Tôi đang tìm cách cập nhật từ điển dict1 với nội dung của bản cập nhật dict khi không ghi đè cấp độA

dictionary1={'level1':{'level2':{'levelA':0,'levelB':1}}}
update={'level1':{'level2':{'levelB':10}}}
dictionary1.update(update)
print dictionary1
{'level1': {'level2': {'levelB': 10}}}

Tôi biết rằng bản cập nhật sẽ xóa các giá trị ở cấp độ 2 vì nó đang cập nhật mức khóa thấp nhất1.

Làm thế nào tôi có thể giải quyết điều này, với từ điển1 và cập nhật có thể có độ dài bất kỳ?


Là làm tổ luôn luôn sâu ba cấp hoặc bạn có thể làm tổ của một độ sâu tùy ý?
BarsheD

Nó có thể có bất kỳ chiều sâu / chiều dài.
jay_t

Sửa lỗi cho tôi nếu tôi sai nhưng có vẻ như giải pháp lý tưởng ở đây đòi hỏi phải thực hiện mẫu thiết kế tổng hợp.
Alexander McN Khoa

Câu trả lời:


263

Câu trả lời của @ FM có ý tưởng chung đúng, nghĩa là một giải pháp đệ quy, nhưng mã hóa hơi kỳ dị và ít nhất một lỗi. Tôi muốn giới thiệu, thay vào đó:

Con trăn 2:

import collections

def update(d, u):
    for k, v in u.iteritems():
        if isinstance(v, collections.Mapping):
            d[k] = update(d.get(k, {}), v)
        else:
            d[k] = v
    return d

Con trăn 3:

import collections.abc

def update(d, u):
    for k, v in u.items():
        if isinstance(v, collections.abc.Mapping):
            d[k] = update(d.get(k, {}), v)
        else:
            d[k] = v
    return d

Các chương trình lỗi lên khi "cập nhật" có một k, vmục nơi vlà một dictkkhông phải là ban đầu là một chìa khóa trong từ điển đang được cập nhật - @ mã "bỏ qua" FM của phần này của bản cập nhật (vì nó thực hiện nó trên một mới có sản phẩm nào dictđó không được lưu hoặc trả lại bất cứ nơi nào, chỉ bị mất khi cuộc gọi đệ quy trở lại).

Những thay đổi khác của tôi là nhỏ: không có lý do nào cho if/ elsexây dựng khi .getthực hiện cùng một công việc nhanh hơn và sạch hơn, và isinstanceđược áp dụng tốt nhất cho các lớp cơ sở trừu tượng (không phải là cụ thể) cho tính tổng quát.


7
+1 Bắt tốt về lỗi - doh! Tôi đoán rằng ai đó sẽ có cách tốt hơn để xử lý isinstancebài kiểm tra, nhưng nghĩ rằng tôi sẽ đâm đầu vào nó.
FMc

6
Một "tính năng" nhỏ khác khiến điều này tăng lên TypeError: 'int' object does not support item assignment.khi bạn, vd update({'k1': 1}, {'k1': {'k2': 2}}). Để thay đổi hành vi này, và thay vào đó mở rộng độ sâu của từ điển để dành chỗ cho từ điển sâu hơn, bạn có thể thêm một elif isinstance(d, Mapping):khoảng d[k] = u[k]và sau isinstanceđiều kiện. Bạn cũng sẽ cần thêm một else: d = {k: u[k]}để đối phó với trường hợp rằng bản cập nhật sâu hơn bản gốc. Rất vui được chỉnh sửa câu trả lời, nhưng không muốn làm bẩn mã súc tích để giải quyết vấn đề của OP.
hobs

1
Tại sao sử dụng isinstance(v, collections.Mapping)chứ không phải isinstance(v, dict)? Trong trường hợp OP quyết định bắt đầu sử dụng bộ sưu tập?
Matt

2
@Matt Yea hoặc bất kỳ đối tượng có nguồn gốc ánh xạ nào khác (danh sách các cặp điều). Làm cho hàm tổng quát hơn và ít có khả năng lặng lẽ bỏ qua các đối tượng có nguồn gốc ánh xạ và khiến chúng không được cập nhật (lỗi ngấm ngầm mà OP có thể không bao giờ nhìn thấy / bắt được). Bạn hầu như luôn muốn sử dụng Ánh xạ để tìm các kiểu dict và basestring để tìm các kiểu str.
hobs

2
Nếu bạn đang chạy cái này trong Python 3+ thay đổi u.iteritems()thành u.items(), nếu không bạn sẽ gặp phải:AttributeError: 'dict' object has no attribute 'iteritems'
Greg K

23

Đã cho tôi biết một chút về điều này, nhưng nhờ bài đăng của @ Alex, anh ấy đã lấp đầy khoảng trống mà tôi đang thiếu. Tuy nhiên, tôi đã gặp một vấn đề nếu một giá trị trong đệ quy dictxảy ra là một list, vì vậy tôi nghĩ tôi muốn chia sẻ và mở rộng câu trả lời của anh ấy.

import collections

def update(orig_dict, new_dict):
    for key, val in new_dict.iteritems():
        if isinstance(val, collections.Mapping):
            tmp = update(orig_dict.get(key, { }), val)
            orig_dict[key] = tmp
        elif isinstance(val, list):
            orig_dict[key] = (orig_dict.get(key, []) + val)
        else:
            orig_dict[key] = new_dict[key]
    return orig_dict

3
Tôi nghĩ rằng điều này có lẽ nên được (để an toàn hơn một chút) : orig_dict.get(key, []) + val.
Andy Hayden

2
Vì các ký tự có thể thay đổi, nên bạn đang thay đổi thể hiện mà bạn đang truyền dưới dạng đối số. Sau đó, bạn không cần phải trả về orig_dict.
gabrielhpugliese

3
Tôi nghĩ rằng hầu hết mọi người sẽ mong đợi định nghĩa sẽ trả về bản chính được cập nhật mặc dù nó được cập nhật tại chỗ.
Kel Solaar

Logic mặc định trong mã của onosendi là nối thêm danh sách đã cập nhật vào danh sách gốc. Nếu bạn cần cập nhật ghi đè lên danh sách gốc, bạn cần đặt orig_dict [key] = val
intijk

1
@gabrielhpugliese trở về bản gốc là cần thiết nếu gọi với một chữ từ điển, ví dụ merged_tree = update({'default': {'initialvalue': 1}}, other_tree)
EoghanM

18

Câu trả lời của @ Alex là tốt, nhưng không hoạt động khi thay thế một yếu tố như số nguyên bằng từ điển, chẳng hạn như update({'foo':0},{'foo':{'bar':1}}). Bản cập nhật này giải quyết nó:

import collections
def update(d, u):
    for k, v in u.iteritems():
        if isinstance(d, collections.Mapping):
            if isinstance(v, collections.Mapping):
                r = update(d.get(k, {}), v)
                d[k] = r
            else:
                d[k] = u[k]
        else:
            d = {k: u[k]}
    return d

update({'k1': 1}, {'k1': {'k2': {'k3': 3}}})

Tôi hiểu rồi. Bạn đã thực hiện elifkiểm tra đối tượng ban đầu của tôi loại điều kiện "kèm theo" có chứa các kiểm tra của cả giá trị và khóa của chính tả / ánh xạ đó. Tài giỏi.
hobs

Điều này sẽ không hoạt động nếu chính tả bên trong có nhiều hơn một khóa.
Wlerin

@Wlerin, nó vẫn hoạt động; d sẽ trở thành một Bản đồ vào thời điểm đó. Đây là một trường hợp thử nghiệm với nhiều khóa : update({'A1': 1, 'A2':2}, {'A1': {'B1': {'C1': 3, 'C2':4}, 'B2':2}, 'A3':5}). Bạn có một ví dụ không làm những gì bạn muốn?
bscan

Tại sao kiểm tra if isinstance(d, collections.Mapping) trên lặp đi lặp lại? Xem câu trả lời của tôi .
Jérôme

13

Giải pháp tương tự như giải pháp được chấp nhận, nhưng đặt tên biến, chuỗi rõ ràng hơn và sửa lỗi trong đó {}giá trị sẽ không ghi đè.

import collections


def deep_update(source, overrides):
    """
    Update a nested dictionary or similar mapping.
    Modify ``source`` in place.
    """
    for key, value in overrides.iteritems():
        if isinstance(value, collections.Mapping) and value:
            returned = deep_update(source.get(key, {}), value)
            source[key] = returned
        else:
            source[key] = overrides[key]
    return source

Dưới đây là một vài trường hợp thử nghiệm:

def test_deep_update():
    source = {'hello1': 1}
    overrides = {'hello2': 2}
    deep_update(source, overrides)
    assert source == {'hello1': 1, 'hello2': 2}

    source = {'hello': 'to_override'}
    overrides = {'hello': 'over'}
    deep_update(source, overrides)
    assert source == {'hello': 'over'}

    source = {'hello': {'value': 'to_override', 'no_change': 1}}
    overrides = {'hello': {'value': 'over'}}
    deep_update(source, overrides)
    assert source == {'hello': {'value': 'over', 'no_change': 1}}

    source = {'hello': {'value': 'to_override', 'no_change': 1}}
    overrides = {'hello': {'value': {}}}
    deep_update(source, overrides)
    assert source == {'hello': {'value': {}, 'no_change': 1}}

    source = {'hello': {'value': {}, 'no_change': 1}}
    overrides = {'hello': {'value': 2}}
    deep_update(source, overrides)
    assert source == {'hello': {'value': 2, 'no_change': 1}}

Chức năng này có sẵn trong gói charlatan , trong charlatan.utils.


7

Đây là một phiên bản bất biến của hợp nhất từ ​​điển đệ quy trong trường hợp bất cứ ai cần nó.

Dựa trên câu trả lời của @Alex Martelli .

Python 2.x:

import collections
from copy import deepcopy


def merge(dict1, dict2):
    ''' Return a new dictionary by merging two dictionaries recursively. '''

    result = deepcopy(dict1)

    for key, value in dict2.iteritems():
        if isinstance(value, collections.Mapping):
            result[key] = merge(result.get(key, {}), value)
        else:
            result[key] = deepcopy(dict2[key])

    return result

Python 3.x:

import collections
from copy import deepcopy


def merge(dict1, dict2):
    ''' Return a new dictionary by merging two dictionaries recursively. '''

    result = deepcopy(dict1)

    for key, value in dict2.items():
        if isinstance(value, collections.Mapping):
            result[key] = merge(result.get(key, {}), value)
        else:
            result[key] = deepcopy(dict2[key])

    return result

6

Những cải tiến nhỏ cho câu trả lời của @ Alex cho phép cập nhật từ điển có độ sâu khác nhau cũng như giới hạn độ sâu mà bản cập nhật đi vào từ điển lồng nhau ban đầu (nhưng độ sâu từ điển cập nhật không bị giới hạn). Chỉ có một vài trường hợp đã được thử nghiệm:

def update(d, u, depth=-1):
    """
    Recursively merge or update dict-like objects. 
    >>> update({'k1': {'k2': 2}}, {'k1': {'k2': {'k3': 3}}, 'k4': 4})
    {'k1': {'k2': {'k3': 3}}, 'k4': 4}
    """

    for k, v in u.iteritems():
        if isinstance(v, Mapping) and not depth == 0:
            r = update(d.get(k, {}), v, depth=max(depth - 1, -1))
            d[k] = r
        elif isinstance(d, Mapping):
            d[k] = u[k]
        else:
            d = {k: u[k]}
    return d

1
Cảm ơn vì điều đó! Trường hợp sử dụng có thể áp dụng tham số độ sâu nào?
Matt

@Matt khi bạn có một số đối tượng / dicts ở độ sâu đã biết mà bạn không muốn hợp nhất / cập nhật, chỉ cần ghi đè lên các đối tượng mới (như thay thế một dict bằng một chuỗi hoặc float hoặc bất cứ điều gì, sâu trong dict của bạn)
hobs

1
Điều này chỉ hoạt động nếu bản cập nhật sâu hơn 1 cấp so với bản gốc. Ví dụ: điều này không thành công: update({'k1': 1}, {'k1': {'k2': {'k3': 3}}})Tôi đã thêm một câu trả lời giải quyết vấn đề này
bscan

@bscan bắt tốt! không bao giờ nghĩ về trường hợp sử dụng đó. Tôi đoán tôi nên tái diễn sâu hơn trong các nhánh elif. Có ý kiến ​​gì không?
hobs

Tại sao thử nghiệm if isinstance(d, Mapping)trên lặp đi lặp lại? Xem câu trả lời của tôi . (Ngoài ra, tôi không chắc về bạn d = {k: u[k]})
Jérôme

4

Câu hỏi này đã cũ, nhưng tôi đã đến đây khi tìm kiếm một giải pháp "hợp nhất sâu". Các câu trả lời trên đã truyền cảm hứng cho những gì sau đây. Cuối cùng tôi đã tự viết vì có lỗi trong tất cả các phiên bản tôi đã thử nghiệm. Điểm quan trọng bị bỏ lỡ là, ở một số độ sâu tùy ý của hai ký tự đầu vào, đối với một số khóa, k, cây quyết định khi d [k] hoặc u [k] không là một lệnh sai.

Ngoài ra, giải pháp này không yêu cầu đệ quy, đối xứng hơn với cách thức dict.update()hoạt động và trả về None.

import collections
def deep_merge(d, u):
   """Do a deep merge of one dict into another.

   This will update d with values in u, but will not delete keys in d
   not found in u at some arbitrary depth of d. That is, u is deeply
   merged into d.

   Args -
     d, u: dicts

   Note: this is destructive to d, but not u.

   Returns: None
   """
   stack = [(d,u)]
   while stack:
      d,u = stack.pop(0)
      for k,v in u.items():
         if not isinstance(v, collections.Mapping):
            # u[k] is not a dict, nothing to merge, so just set it,
            # regardless if d[k] *was* a dict
            d[k] = v
         else:
            # note: u[k] is a dict

            # get d[k], defaulting to a dict, if it doesn't previously
            # exist
            dv = d.setdefault(k, {})

            if not isinstance(dv, collections.Mapping):
               # d[k] is not a dict, so just set it to u[k],
               # overriding whatever it was
               d[k] = v
            else:
               # both d[k] and u[k] are dicts, push them on the stack
               # to merge
               stack.append((dv, v))

4

Chỉ cần sử dụng python-benedict (tôi đã làm nó) , nó có một mergephương thức tiện ích (deepupdate) và nhiều phương thức khác. Nó hoạt động với python 2 / python 3 và nó đã được thử nghiệm tốt.

from benedict import benedict

dictionary1=benedict({'level1':{'level2':{'levelA':0,'levelB':1}}})
update={'level1':{'level2':{'levelB':10}}}
dictionary1.merge(update)
print(dictionary1)
# >> {'level1':{'level2':{'levelA':0,'levelB':10}}}

Cài đặt: pip install python-benedict

Tài liệu: https://github.com/fabiocaccamo/python-benedict


2

Trong cả hai câu trả lời này, các tác giả dường như hiểu khái niệm cập nhật một đối tượng được lưu trữ trong từ điển cũng như thậm chí không lặp lại các mục trong từ điển (trái ngược với các khóa). Vì vậy, tôi đã phải viết một cái mà không tạo ra các cửa hàng và truy xuất từ ​​điển tautological vô nghĩa. Các dicts được giả định để lưu trữ các dicts khác hoặc các loại đơn giản.

def update_nested_dict(d, other):
    for k, v in other.items():
        if isinstance(v, collections.Mapping):
            d_v = d.get(k)
            if isinstance(d_v, collections.Mapping):
                update_nested_dict(d_v, v)
            else:
                d[k] = v.copy()
        else:
            d[k] = v

Hoặc thậm chí đơn giản hơn làm việc với bất kỳ loại nào:

def update_nested_dict(d, other):
    for k, v in other.items():
        d_v = d.get(k)
        if isinstance(v, collections.Mapping) and isinstance(d_v, collections.Mapping):
            update_nested_dict(d_v, v)
        else:
            d[k] = deepcopy(v) # or d[k] = v if you know what you're doing

2

Cập nhật câu trả lời của @Alex Martelli để sửa lỗi trong mã của anh ấy để làm cho giải pháp mạnh mẽ hơn:

def update_dict(d, u):
    for k, v in u.items():
        if isinstance(v, collections.Mapping):
            default = v.copy()
            default.clear()
            r = update_dict(d.get(k, default), v)
            d[k] = r
        else:
            d[k] = v
    return d

Điều quan trọng là chúng ta thường muốn tạo cùng một kiểu khi đệ quy, vì vậy ở đây chúng ta sử dụng v.copy().clear()nhưng không {}. Và điều này đặc biệt hữu ích nếu dictở đây thuộc loại collections.defaultdictcó thể có các loại default_factorys khác nhau .

Cũng lưu ý rằng u.iteritems()đã được thay đổi thành u.items()trong Python3.


2

Tôi đã sử dụng giải pháp @Alex Martelli gợi ý, nhưng không thành công

TypeError 'bool' object does not support item assignment

khi hai từ điển khác nhau về kiểu dữ liệu ở một mức độ nào đó.

Trong trường hợp ở cùng cấp, phần tử của từ điển dchỉ là vô hướng (tức là Bool) trong khi phần tử của từ điển uvẫn là từ điển, việc gán lại không thành công vì không thể gán từ điển vào vô hướng (nhưTrue[k] ).

Một điều kiện bổ sung sửa chữa rằng:

from collections import Mapping

def update_deep(d, u):
    for k, v in u.items():
        # this condition handles the problem
        if not isinstance(d, Mapping):
            d = u
        elif isinstance(v, Mapping):
            r = update_deep(d.get(k, {}), v)
            d[k] = r
        else:
            d[k] = u[k]

    return d

2

Mã dưới đây sẽ giải quyết update({'k1': 1}, {'k1': {'k2': 2}})vấn đề trong câu trả lời của @Alex Martelli đúng cách.

def deepupdate(original, update):
    """Recursively update a dict.

    Subdict's won't be overwritten but also updated.
    """
    if not isinstance(original, abc.Mapping):
        return update
    for key, value in update.items():
        if isinstance(value, abc.Mapping):
            original[key] = deepupdate(original.get(key, {}), value)
        else:
            original[key] = value
    return original

1
def update(value, nvalue):
    if not isinstance(value, dict) or not isinstance(nvalue, dict):
        return nvalue
    for k, v in nvalue.items():
        value.setdefault(k, dict())
        if isinstance(v, dict):
            v = update(value[k], v)
        value[k] = v
    return value

sử dụng dicthoặccollections.Mapping


1

Tôi biết câu hỏi này khá cũ, nhưng vẫn đăng những gì tôi làm khi tôi phải cập nhật một từ điển lồng nhau. Chúng ta có thể sử dụng thực tế là các ký tự được truyền bằng tham chiếu trong python Giả sử rằng đường dẫn của khóa được biết và được phân tách bằng dấu chấm. Forex nếu chúng ta có một dữ liệu có tên chính tả:

{
"log_config_worker": {
    "version": 1, 
    "root": {
        "handlers": [
            "queue"
        ], 
        "level": "DEBUG"
    }, 
    "disable_existing_loggers": true, 
    "handlers": {
        "queue": {
            "queue": null, 
            "class": "myclass1.QueueHandler"
        }
    }
}, 
"number_of_archived_logs": 15, 
"log_max_size": "300M", 
"cron_job_dir": "/etc/cron.hourly/", 
"logs_dir": "/var/log/patternex/", 
"log_rotate_dir": "/etc/logrotate.d/"
}

Và chúng tôi muốn cập nhật lớp xếp hàng, đường dẫn của khóa sẽ là - log_config_worker.handlers.queue.class

Chúng ta có thể sử dụng chức năng sau để cập nhật giá trị:

def get_updated_dict(obj, path, value):
    key_list = path.split(".")

    for k in key_list[:-1]:
        obj = obj[k]

    obj[key_list[-1]] = value

get_updated_dict(data, "log_config_worker.handlers.queue.class", "myclass2.QueueHandler")

Điều này sẽ cập nhật từ điển chính xác.


1

Nó có thể là bạn vấp phải một từ điển không chuẩn, như tôi ngày nay, không có iteritems-Attribution. Trong trường hợp này, thật dễ dàng để hiểu loại từ điển này là một từ điển tiêu chuẩn. Ví dụ: Python 2.7:

    import collections
    def update(orig_dict, new_dict):
        for key, val in dict(new_dict).iteritems():
            if isinstance(val, collections.Mapping):
                tmp = update(orig_dict.get(key, { }), val)
                orig_dict[key] = tmp
            elif isinstance(val, list):
                orig_dict[key] = (orig_dict[key] + val)
            else:
                orig_dict[key] = new_dict[key]
        return orig_dict

    import multiprocessing
    d=multiprocessing.Manager().dict({'sample':'data'})
    u={'other': 1234}

    x=update(d, u)
    x.items()

Con trăn 3,8:

    def update(orig_dict, new_dict):
        orig_dict=dict(orig_dict)
        for key, val in dict(new_dict).items():
            if isinstance(val, collections.abc.Mapping):
                tmp = update(orig_dict.get(key, { }), val)
                orig_dict[key] = tmp
            elif isinstance(val, list):
                orig_dict[key] = (orig_dict[key] + val)
            else:
                orig_dict[key] = new_dict[key]
        return orig_dict

    import collections
    import multiprocessing
    d=multiprocessing.Manager().dict({'sample':'data'})
    u={'other': 1234, "deeper": {'very': 'deep'}}

    x=update(d, u)
    x.items()

0

Đúng! Và một giải pháp khác. Giải pháp của tôi khác nhau trong các phím đang được kiểm tra. Trong tất cả các giải pháp khác, chúng tôi chỉ nhìn vào các phím trongdict_b . Nhưng ở đây chúng tôi nhìn vào sự kết hợp của cả hai từ điển.

Làm với nó như bạn muốn

def update_nested(dict_a, dict_b):
    set_keys = set(dict_a.keys()).union(set(dict_b.keys()))
    for k in set_keys:
        v = dict_a.get(k)
        if isinstance(v, dict):
            new_dict = dict_b.get(k, None)
            if new_dict:
                update_nested(v, new_dict)
        else:
            new_value = dict_b.get(k, None)
            if new_value:
                dict_a[k] = new_value

0

Nếu bạn muốn thay thế "từ điển lồng nhau đầy đủ bằng mảng", bạn có thể sử dụng đoạn mã này:

Nó sẽ thay thế bất kỳ "old_value" bằng "new_value". Nó gần như đang thực hiện việc xây dựng lại từ điển theo chiều sâu. Nó thậm chí có thể hoạt động với List hoặc Str / int được đưa ra làm tham số đầu vào của cấp độ đầu tiên.

def update_values_dict(original_dict, future_dict, old_value, new_value):
    # Recursively updates values of a nested dict by performing recursive calls

    if isinstance(original_dict, Dict):
        # It's a dict
        tmp_dict = {}
        for key, value in original_dict.items():
            tmp_dict[key] = update_values_dict(value, future_dict, old_value, new_value)
        return tmp_dict
    elif isinstance(original_dict, List):
        # It's a List
        tmp_list = []
        for i in original_dict:
            tmp_list.append(update_values_dict(i, future_dict, old_value, new_value))
        return tmp_list
    else:
        # It's not a dict, maybe a int, a string, etc.
        return original_dict if original_dict != old_value else new_value

0

Một cách khác để sử dụng đệ quy:

def updateDict(dict1,dict2):
    keys1 = list(dict1.keys())
    keys2= list(dict2.keys())
    keys2 = [x for x in keys2 if x in keys1]
    for x in keys2:
        if (x in keys1) & (type(dict1[x]) is dict) & (type(dict2[x]) is dict):
            updateDict(dict1[x],dict2[x])
        else:
            dict1.update({x:dict2[x]})
    return(dict1)

0

một Q mới làm thế nào để bằng chuỗi khóa

dictionary1={'level1':{'level2':{'levelA':0,'levelB':1}},'anotherLevel1':{'anotherLevel2':{'anotherLevelA':0,'anotherLevelB':1}}}
update={'anotherLevel1':{'anotherLevel2':1014}}
dictionary1.update(update)
print dictionary1
{'level1':{'level2':{'levelA':0,'levelB':1}},'anotherLevel1':{'anotherLevel2':1014}}

0

bạn có thể thử cái này, nó hoạt động với các danh sách và hoàn toàn:

def update_keys(newd, dic, mapping):
  def upsingle(d,k,v):
    if k in mapping:
      d[mapping[k]] = v
    else:
      d[k] = v
  for ekey, evalue in dic.items():
    upsingle(newd, ekey, evalue)
    if type(evalue) is dict:
      update_keys(newd, evalue, mapping)
    if type(evalue) is list:
      upsingle(newd, ekey, [update_keys({}, i, mapping) for i in evalue])
  return newd

0

Tôi khuyên bạn nên thay thế {}bằng cách type(v)()truyền bá loại đối tượng của bất kỳ lớp con dict nào được lưu trữ unhưng không có d. Ví dụ: điều này sẽ bảo tồn các loại như bộ sưu tập.OrderedDict:

Con trăn 2:

import collections

def update(d, u):
    for k, v in u.iteritems():
        if isinstance(v, collections.Mapping):
            d[k] = update(d.get(k, type(v)()), v)
        else:
            d[k] = v
    return d

Con trăn 3:

import collections.abc

def update(d, u):
    for k, v in u.items():
        if isinstance(v, collections.abc.Mapping):
            d[k] = update(d.get(k, type(v)()), v)
        else:
            d[k] = v
    return d

-1

Đó là một chút sang một bên nhưng bạn có thực sự cần từ điển lồng nhau? Tùy thuộc vào vấn đề, đôi khi từ điển phẳng có thể đủ ... và nhìn tốt về nó:

>>> dict1 = {('level1','level2','levelA'): 0}
>>> dict1['level1','level2','levelB'] = 1
>>> update = {('level1','level2','levelB'): 10}
>>> dict1.update(update)
>>> print dict1
{('level1', 'level2', 'levelB'): 10, ('level1', 'level2', 'levelA'): 0}

5
Cấu trúc lồng nhau đến từ các bộ dữ liệu json đến, vì vậy tôi muốn giữ nguyên chúng, ...
jay_t

-1

Nếu bạn muốn một lớp lót:

{**dictionary1, **{'level1':{**dictionary1['level1'], **{'level2':{**dictionary1['level1']['level2'], **{'levelB':10}}}}}}
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.