अलग-अलग गहराई के एक नेस्टेड शब्दकोश का अद्यतन मूल्य


162

मैं तानाशाही अधिलेखित लेवल अपडेट की सामग्री के साथ डिक्शनरी डिक्शनरी 1 को अपडेट करने का एक तरीका खोज रहा हूं

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

मुझे पता है कि अद्यतन Level2 में मानों को हटा देता है क्योंकि यह सबसे महत्वपूर्ण कुंजी Level1 को अद्यतन कर रहा है।

मैं इसे कैसे निपटा सकता हूं, यह देखते हुए कि डिक्शनरी 1 और अपडेट की कोई लंबाई हो सकती है?


क्या घोंसला हमेशा तीन स्तरों पर गहरा होता है या क्या आपके पास एक मनमानी गहराई का घोंसला हो सकता है?
क्रिस्टोफडी

इसकी कोई भी गहराई / लंबाई हो सकती है।
jay_t

मुझे सही करें अगर मैं गलत हूं, लेकिन ऐसा लगता है कि यहां आदर्श समाधान को समग्र डिजाइन पैटर्न के कार्यान्वयन की आवश्यकता है।
अलेक्जेंडर मैकनैकेर

जवाबों:


263

@ एफएम के जवाब में सही सामान्य विचार है, यानी पुनरावर्ती समाधान, लेकिन कुछ अजीबोगरीब कोडिंग और कम से कम एक बग। मैं इसके बजाय सलाह देता हूं:

अजगर 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

अजगर 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

बग तब दिखाई देता है जब "अपडेट" में ए k, vआइटम vहोता है, जो कि एक है dictऔर kमूल रूप से शब्दकोश में एक कुंजी नहीं है जिसे अपडेट किया जा रहा है - @ एफएम का कोड "अपडेट" करता है (क्योंकि यह इसे एक खाली नए पर करता है dictजो बचाया नहीं गया है या कहीं भी लौटा है, जब पुनरावर्ती कॉल वापस आ जाता है)।

मेरे अन्य परिवर्तन मामूली हैं: जब समान कार्य तेजी से और साफ होता है, तो if/ elseनिर्माण का कोई कारण नहीं .getहोता है, और isinstanceयह सामान्यता के लिए अमूर्त आधार वर्गों (ठोस नहीं) पर लागू होता है।


7
+1 बग पर अच्छी पकड़ - दोह! मुझे लगा कि किसी के पास isinstanceपरीक्षण को संभालने का एक बेहतर तरीका होगा , लेकिन मैंने सोचा कि मैं इस पर एक कदम उठाऊंगा।
FMc

6
एक और मामूली "फीचर" इसका कारण बनता है TypeError: 'int' object does not support item assignment.जब आप, जैसे update({'k1': 1}, {'k1': {'k2': 2}})। इस व्यवहार को बदलने के लिए, और इसके बजाय शब्दकोशों की गहराई का विस्तार करके गहन शब्दकोशों के लिए जगह बनाएं जो आप हालत के elif isinstance(d, Mapping):आसपास d[k] = u[k]और उसके बाद जोड़ सकते हैं isinstance। आपको else: d = {k: u[k]}इस मामले से निपटने के लिए एक जोड़ने की आवश्यकता होगी कि अद्यतन तानाशाही मूल ताना की तुलना में गहरा है। उत्तर को संपादित करने के लिए खुश है, लेकिन ओपी की समस्या को हल करने वाले संक्षिप्त कोड को गंदा नहीं करना चाहते हैं।
होब्स

1
isinstance(v, collections.Mapping)बजाय उपयोग क्यों isinstance(v, dict)? इस घटना में कि ओपी संग्रह का उपयोग शुरू करने का फैसला करता है?
मैट

2
@ मैट या, या किसी अन्य मानचित्रण-व्युत्पन्न वस्तु (चीजों के जोड़े की सूची)। फ़ंक्शन को अधिक सामान्य बनाता है और मैपिंग-व्युत्पन्न ऑब्जेक्ट्स को चुपचाप अनदेखा करने और उन्हें अन-अपडेटेड (कपटपूर्ण त्रुटि जो ओपी कभी भी नहीं देख सकता / छोड़ सकता है) को छोड़ देता है। आप लगभग हमेशा प्रकारों को खोजने के लिए तानाशाही प्रकारों और बेसरेस्ट्रिंग को खोजने के लिए मैपिंग का उपयोग करना चाहते हैं।
होब्स

2
आप अजगर 3+ परिवर्तन के तहत इस चला रहे हैं u.iteritems()करने के लिए u.items(), अन्यथा आप का सामना करेंगे:AttributeError: 'dict' object has no attribute 'iteritems'
ग्रेग कश्मीर

23

मुझे इस पर एक छोटा सा ले लिया, लेकिन @ एलेक्स के पद के लिए धन्यवाद, वह उस खाई में भर गया जो मैं गायब था। हालाँकि, मैं एक मुद्दे पर आया था यदि पुनरावर्ती के भीतर एक मूल्य dictहोता है a list, तो मैंने सोचा कि मैं साझा करूंगा, और उसके उत्तर का विस्तार करूंगा।

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
मुझे लगता है कि यह शायद (थोड़ा सुरक्षित होने के लिए) होना चाहिए orig_dict.get(key, []) + val:।
एंडी हेडन

2
चूँकि dicts परस्पर हैं, आप उदाहरण को तर्क के रूप में बदल रहे हैं। फिर, आपको ओरिजिनल_डक्ट वापस करने की आवश्यकता नहीं है।
गाब्रिएलपग्लाइसे

3
मुझे लगता है कि अधिकांश लोगों को यह उम्मीद होती है कि परिभाषा अद्यतन होने के बावजूद भी यह अद्यतन की जाएगी।
केल सोलर

ओनोसेंडी के कोड में डिफ़ॉल्ट तर्क अद्यतन सूची को मूल सूची में जोड़ना है। यदि आपको मूल सूची को अधिलेखित करने की आवश्यकता है, तो आपको
intijk

1
@gabrielhpugliese को मूल लौटाने की जरूरत है अगर एक शब्दकोश शाब्दिक के साथ बुलाया जाता है, जैसे merged_tree = update({'default': {'initialvalue': 1}}, other_tree)
EoghanM

18

@ एलेक्स का जवाब अच्छा है, लेकिन एक शब्दकोश के साथ पूर्णांक जैसे तत्व को प्रतिस्थापित करते समय काम नहीं करता है, जैसे कि update({'foo':0},{'foo':{'bar':1}})। यह अपडेट इसे संबोधित करता है:

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}}})

समझा। आपने elifमूल वस्तु के मेरे चेक को एक "एन्क्लोजिंग" सशर्त बनाया, जिसमें मूल्य और उस मैपिंग दोनों की जांच शामिल थी। चतुर।
हॉब्स

यह काम नहीं करेगा अगर आंतरिक ताना एक से अधिक कुंजी है।
वॉलरिन

@Wlerin, यह अभी भी काम करता है; d उस बिंदु से मैपिंग बन गया होगा। यहाँ कई कुंजी के साथ एक परीक्षण मामला है update({'A1': 1, 'A2':2}, {'A1': {'B1': {'C1': 3, 'C2':4}, 'B2':2}, 'A3':5}):। क्या आपके पास एक उदाहरण है जो आप नहीं चाहते हैं?
15

if isinstance(d, collections.Mapping)Evey पुनरावृत्ति पर परीक्षण क्यों ? मेरा जवाब देखिए ।
14:20 पर Jérôme

13

एक ही समाधान के रूप में स्वीकार किए जाते हैं, लेकिन स्पष्ट चर नामकरण, docstring, और एक बग तय किया है जहां {}एक मूल्य के रूप में ओवरराइड नहीं होगा।

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

यहाँ कुछ परीक्षण मामले हैं:

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}}

यह कार्य चार्लटन पैकेज, में उपलब्ध है charlatan.utils


7

यदि किसी को इसकी आवश्यकता है, तो यहां पुनरावर्ती शब्दकोश विलय का एक अपरिवर्तनीय संस्करण है।

@Alex मार्टेली के जवाब के आधार पर ।

पायथन 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

अजगर 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

@ एलेक्स के उत्तर में मामूली सुधार, जो अलग-अलग गहराई के शब्दकोशों को अपडेट करने में सक्षम बनाता है और साथ ही गहराई को सीमित करता है कि अपडेट मूल नेस्टेड डिक्शनरी में गोताखोरी करता है (लेकिन अपडेट डिक्शनरी की गहराई सीमित नहीं है)। केवल कुछ मामलों का परीक्षण किया गया है:

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
इसके लिए धन्यवाद! गहराई पैरामीटर किस उपयोग-मामले पर लागू हो सकता है?
मैट

@ मैट जब आप कुछ वस्तुओं / dicts एक ज्ञात गहराई पर है कि आप विलय / अद्यतन नहीं करना चाहते हैं, बस नई वस्तुओं के साथ अधिलेखित (जैसे एक स्ट्रिंग के साथ एक हुक या नाव या जो कुछ भी, अपने तानाशाही में गहरा)
hobs

1
यह केवल तभी काम करता है जब अपडेट मूल से अधिक 1 स्तर पर हो। उदाहरण के लिए, यह विफल रहता है: update({'k1': 1}, {'k1': {'k2': {'k3': 3}}})मैंने एक उत्तर जोड़ा है जो इस पते पर है
bscan

@bscan अच्छी पकड़! उस उपयोग के मामले के बारे में कभी नहीं सोचा था। मुझे लगता है कि मुझे एलिफ शाखाओं में गहराई से पुनरावृत्ति करनी चाहिए। कोई विचार?
hobs

if isinstance(d, Mapping)Evey पुनरावृत्ति पर परीक्षण क्यों ? मेरा जवाब देखिए । (इसके अलावा, मैं आपके बारे में निश्चित नहीं हूं d = {k: u[k]})
जेरोम

4

यह प्रश्न पुराना है, लेकिन मैं "गहरे मर्ज" समाधान की खोज करते समय यहां उतरा। ऊपर दिए गए उत्तर इस प्रकार हैं। मैंने अपना लेखन लिखना समाप्त कर दिया क्योंकि मेरे द्वारा परीक्षण किए गए सभी संस्करणों में बग थे। महत्वपूर्ण बिंदु याद किया गया था, दो इनपुट डिक्सेस की कुछ मनमानी गहराई पर, कुछ कुंजी के लिए, निर्णय वृक्ष, जब डी [के] या यू [के] एक तानाशाह नहीं था, दोषपूर्ण था।

इसके अलावा, इस समाधान में पुनरावृत्ति की आवश्यकता नहीं है, जो कि कैसे dict.update()काम करता है और रिटर्न के साथ अधिक सममित है 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

बस उपयोग करें python-benedict (मैंने इसे किया था) , इसकी एक merge(गहरी) उपयोगिता विधि और कई अन्य हैं। यह अजगर 2 / अजगर 3 के साथ काम करता है और यह अच्छी तरह से परीक्षण किया गया है।

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}}}

स्थापना: pip install python-benedict

प्रलेखन: https://github.com/fabiocaccamo/python-benedict


2

इनमें से किसी भी उत्तर में लेखक किसी शब्दकोश में संग्रहित किसी वस्तु को अद्यतन करने की अवधारणा को नहीं समझता है और न ही शब्दकोश की वस्तुओं पर ध्यान देने योग्य है (जैसा कि कुंजियों के विपरीत है)। इसलिए मुझे एक लिखना पड़ा, जो व्यर्थ के शब्दकोषों को शब्दकोश स्टोर और रिट्रीवल नहीं बनाता। Dicts को अन्य डाइक या सरल प्रकारों को संग्रहीत करने के लिए माना जाता है।

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

या किसी भी प्रकार के साथ काम करने वाले को भी सरल बनाना:

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

समाधान को अधिक मजबूत बनाने के लिए अपने कोड में बग को ठीक करने के लिए @Alex मार्टेली के उत्तर को अपडेट करें:

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

कुंजी यह है कि हम अक्सर एक ही प्रकार की पुनरावृत्ति पर बनाना चाहते हैं , इसलिए यहां हम उपयोग करते हैं, v.copy().clear()लेकिन नहीं {}। और यह विशेष रूप से उपयोगी है अगर dictयहाँ प्रकार है collections.defaultdictजो विभिन्न प्रकार के हो सकते हैं default_factory

यह भी ध्यान दें कि u.iteritems()में बदल दिया गया u.items()है Python3


2

मैंने समाधान का उपयोग किया @Alex Martelli सुझाव देता है, लेकिन यह विफल रहता है

TypeError 'bool' object does not support item assignment

जब दोनों शब्दकोश कुछ स्तर पर डेटा प्रकार में भिन्न होते हैं।

मामले में एक ही स्तर पर शब्दकोश dका तत्व सिर्फ एक अदिश राशि है (यानी। Bool) जबकि शब्दकोश uका तत्व अभी भी शब्दकोश है पुनर्मूल्यांकन विफल रहता है क्योंकि कोई शब्द असाइनमेंट स्केलर (जैसे True[k]) में संभव नहीं है ।

एक जोड़ा हालत सुधारता है कि:

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

नीचे दिए गए कोड update({'k1': 1}, {'k1': {'k2': 2}})@Alex Martelli के उत्तर को सही तरीके से हल करना चाहिए ।

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

उपयोग dictयाcollections.Mapping


1

मुझे पता है कि यह सवाल बहुत पुराना है, लेकिन फिर भी जब मैं एक नेस्टेड डिक्शनरी को अपडेट करना होता है, तो मैं पोस्ट करता हूं। हम इस तथ्य का उपयोग कर सकते हैं कि डाइक को अजगर में संदर्भ द्वारा पारित किया गया है यह मानते हुए कि कुंजी का मार्ग ज्ञात है और डॉट अलग हो गया है। विदेशी मुद्रा यदि हमारे पास एक नामांकित डेटा है:

{
"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/"
}

और हम कतार वर्ग को अद्यतन करना चाहते हैं, कुंजी का मार्ग होगा - log_config_worker.handlers.queue.class

हम मान को अद्यतन करने के लिए निम्नलिखित फ़ंक्शन का उपयोग कर सकते हैं:

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")

यह शब्दकोश को सही ढंग से अद्यतन करेगा।


1

यह हो सकता है कि आप मेरे जैसे गैर-मानक-शब्दकोश पर ठोकर खाएं, जिसमें कोई पुनरावृति-गुण नहीं है। इस मामले में इस प्रकार के शब्दकोश को एक मानक-शब्दकोश के रूप में व्याख्या करना आसान है। जैसे: पायथन 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()

पायथन 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

हाँ! और दूसरा उपाय। मेरा समाधान उन कुंजियों में भिन्न होता है जिन्हें जांचा जा रहा है। अन्य सभी समाधानों में हम केवल कुंजियों को देखते हैं dict_b। लेकिन यहाँ हम दोनों शब्दकोशों के मिलन को देखते हैं।

आप कृपा करके इसे करें

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

यदि आप "सरणियों के साथ पूर्ण नेस्टेड शब्दकोश" को बदलना चाहते हैं, तो आप इस स्निपेट का उपयोग कर सकते हैं:

यह किसी भी "old_value" को "new_value" से बदल देगा। यह शब्दकोश की गहराई से पहला पुनर्निर्माण कर रहा है। यह पहले स्तर के इनपुट पैरामीटर के रूप में दी गई सूची या Str / int के साथ भी काम कर सकता है।

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

पुनरावृत्ति का उपयोग करने का दूसरा तरीका:

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

एक नया क्यू कैसे एक कुंजी श्रृंखला द्वारा

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

आप यह कोशिश कर सकते हैं, यह सूचियों के साथ काम करता है और शुद्ध है:

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

मैं बदलने के लिए सलाह देते हैं {}द्वारा type(v)()किसी भी dict उपवर्ग में संग्रहीत की प्रचार ऑब्जेक्ट प्रकार के क्रम में uलेकिन से अनुपस्थित d। उदाहरण के लिए, यह संग्रह जैसे प्रकारों को संरक्षित करेगा।

अजगर 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

अजगर 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

यह पक्ष के लिए थोड़ा सा है लेकिन क्या आपको वास्तव में नेस्टेड शब्दकोशों की आवश्यकता है? समस्या के आधार पर, कभी-कभी सपाट शब्दकोश पर्याप्त हो सकता है ... और उस पर अच्छा लगेगा:

>>> 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
नेस्टेड संरचना आने वाले जॉन्स डेटासेट से आती है, इसलिए मैं उन्हें बरकरार रखना चाहूंगा, ...
jay_t

-1

यदि आप एक-लाइनर चाहते हैं:

{**dictionary1, **{'level1':{**dictionary1['level1'], **{'level2':{**dictionary1['level1']['level2'], **{'levelB':10}}}}}}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.