सवाल एक अभिव्यक्ति में दो शब्दकोशों को कैसे विलय करें?


मेरे पास दो पायथन शब्दकोश हैं, और मैं एक एकल अभिव्यक्ति लिखना चाहता हूं जो इन दो शब्दकोशों को लौटाता है, विलय हो जाता है। update() विधि की आवश्यकता होगी, अगर यह एक जगह में एक नियम को संशोधित करने के बजाय इसके परिणाम लौटा दिया।

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = x.update(y)
>>> print(z)
None
>>> x
{'a': 1, 'b': 10, 'c': 11}

मैं उस अंतिम विलय किए गए निर्देश को कैसे प्राप्त कर सकता हूं z, नहीं x?

(अतिरिक्त स्पष्ट होने के लिए, अंतिम-एक-जीत संघर्ष-हैंडलिंग dict.update() मैं भी यही देख रहा हूं।)


3222
2017-09-02 07:44


मूल




जवाब:


मैं एक ही अभिव्यक्ति में दो पायथन शब्दकोश कैसे विलय कर सकता हूं?

शब्दकोश के लिए x तथा y, z मूल्यों के साथ एक विलय शब्दकोश बन जाता है y उनको बदलना x

  • पाइथन 3.5 या उससे अधिक में:

    z = {**x, **y}
    w = {'foo': 'bar', 'baz': 'qux', **y}  # merge a dict with literal values
    
  • पायथन 2 में, (या 3.4 या निचला) एक फ़ंक्शन लिखें:

    def merge_two_dicts(x, y):
        z = x.copy()   # start with x's keys and values
        z.update(y)    # modifies z with y's keys and values & returns None
        return z
    

    तथा

    z = merge_two_dicts(x, y)
    

व्याख्या

मान लें कि आपके पास दो डिक्ट्स हैं और आप मूल डिक्ट्स को बदलने के बिना उन्हें नए नियम में विलय करना चाहते हैं:

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

वांछित परिणाम एक नया शब्दकोश प्राप्त करना है (z) मूल्यों के विलय के साथ, और दूसरे dict के मूल्य पहले से ओवरराइटिंग।

>>> z
{'a': 1, 'b': 3, 'c': 4}

इसके लिए एक नया वाक्यविन्यास, प्रस्तावित पीईपी 448 तथा पाइथन 3.5 के रूप में उपलब्ध है, है

z = {**x, **y}

और यह वास्तव में एक अभिव्यक्ति है। यह अब में लागू के रूप में दिखा रहा है 3.5, पीईपी 478 के लिए रिलीज शेड्यूल, और अब यह अपना रास्ता बना दिया है पाइथन 3.5 में नया क्या है दस्तावेज़।

हालांकि, चूंकि कई संगठन अभी भी पायथन 2 पर हैं, इसलिए आप इसे पीछे के संगत तरीके से करना चाहेंगे। पाइथन 2 और पायथन 3.0-3.4 में उपलब्ध शास्त्रीय पायथनिक तरीका, इसे दो-चरणीय प्रक्रिया के रूप में करना है:

z = x.copy()
z.update(y) # which returns None since it mutates z

दोनों दृष्टिकोणों में, y दूसरा आ जाएगा और इसके मूल्य बदल जाएंगे xइस तरह के मूल्य 'b' इंगित करेगा 3 हमारे अंतिम परिणाम में।

अभी तक पायथन 3.5 पर नहीं, लेकिन एक चाहते हैं एकल अभिव्यक्ति

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

def merge_two_dicts(x, y):
    """Given two dicts, merge them into a new dict as a shallow copy."""
    z = x.copy()
    z.update(y)
    return z

और फिर आपके पास एक अभिव्यक्ति है:

z = merge_two_dicts(x, y)

आप शून्य से एक बहुत बड़ी संख्या में, एक अपरिभाषित संख्या में विलयों को मर्ज करने के लिए एक फ़ंक्शन भी बना सकते हैं:

def merge_dicts(*dict_args):
    """
    Given any number of dicts, shallow copy and merge into a new dict,
    precedence goes to key value pairs in latter dicts.
    """
    result = {}
    for dictionary in dict_args:
        result.update(dictionary)
    return result

यह फ़ंक्शन सभी डिक्ट्स के लिए पायथन 2 और 3 में काम करेगा। जैसे दी गई दी गई a सेवा मेरे g:

z = merge_dicts(a, b, c, d, e, f, g) 

और कुंजी मूल्य जोड़ों में g डिक्ट्स पर प्राथमिकता लेंगे a सेवा मेरे f, और इसी तरह।

अन्य उत्तरों की आलोचनाएं

पूर्व में स्वीकृत उत्तर में जो भी आप देखते हैं उसका उपयोग न करें:

z = dict(x.items() + y.items())

पायथन 2 में, आप प्रत्येक निर्देश के लिए स्मृति में दो सूचियां बनाते हैं, स्मृति में तीसरी सूची बनाते हैं, जिसमें पहले दो की लंबाई के बराबर लंबाई होती है, और फिर सभी तीन सूचियों को निर्देश बनाने के लिए छोड़ दें। पायथन 3 में, यह असफल हो जाएगा क्योंकि आप दो जोड़ रहे हैं dict_items एक साथ वस्तुओं, दो सूचियों नहीं -

>>> c = dict(a.items() + b.items())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'dict_items' and 'dict_items'

और आपको उन्हें सूचियों के रूप में स्पष्ट रूप से बनाना होगा, उदा। z = dict(list(x.items()) + list(y.items()))। यह संसाधनों और गणना शक्ति का अपशिष्ट है।

इसी प्रकार, संघ का अधिग्रहण करना items()पायथन 3 में (viewitems() पायथन 2.7 में) भी असफल हो जाएंगे जब मूल्य अस्थिर वस्तुओं (जैसे सूचियों, उदाहरण के लिए) हैं। भले ही आपके मूल्य हर्षनीय हैं, चूंकि सेट अर्थात् अनियंत्रित होते हैं, वरीयता को प्राथमिकता के संबंध में अपरिभाषित किया जाता है। तो ऐसा मत करो:

>>> c = dict(a.items() | b.items())

यह उदाहरण दर्शाता है कि क्या होता है जब मूल्य अचूक होते हैं:

>>> x = {'a': []}
>>> y = {'b': []}
>>> dict(x.items() | y.items())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

यहां एक उदाहरण दिया गया है जहां y को प्राथमिकता होनी चाहिए, लेकिन सेट के मनमानी क्रम के कारण x से मान को बनाए रखा गया है:

>>> x = {'a': 2}
>>> y = {'a': 1}
>>> dict(x.items() | y.items())
{'a': 2}

एक और हैक जिसका आप उपयोग नहीं करना चाहिए:

z = dict(x, **y)

यह उपयोग करता है dict कन्स्ट्रक्टर, और बहुत तेज़ और मेमोरी कुशल है (यहां तक ​​कि हमारी दो-चरणीय प्रक्रिया की तुलना में थोड़ा और भी) लेकिन जब तक आप यह नहीं जानते कि यहां क्या हो रहा है (यानी, दूसरा नियम दंड कन्स्ट्रक्टर को कीवर्ड तर्क के रूप में पारित किया जा रहा है) इसे पढ़ना मुश्किल है, यह इच्छित उपयोग नहीं है, और इसलिए यह पाइथोनिक नहीं है।

उपयोग का एक उदाहरण यहां दिया गया है django में remediated

डिक्ट्स का उद्देश्य हैशबल कुंजियां (जैसे फ्रोजनसेट या टुपल्स) लेना है, लेकिन यह विधि पायथन 3 में विफल होती है जब चाबियाँ तार नहीं होती हैं।

>>> c = dict(a, **b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings

वहाँ से मेलिंग सूची, भाषा के निर्माता, Guido वैन Rossum, लिखा था:

मैं ठीक हूँ   घोषित घोषित करना ({}, ** {1: 3}) अवैध, क्योंकि आखिरकार इसका दुरुपयोग है   यांत्रिकी।

तथा

स्पष्ट रूप से dict (x, ** y) "कॉल के लिए" कूल हैक "के रूप में चारों ओर जा रहा है   x.update (y) और वापसी x "। व्यक्तिगत रूप से मुझे इससे अधिक घृणास्पद लगता है   ठंडा।

यह मेरी समझ है (साथ ही साथ की समझ भी भाषा के निर्माता) के लिए इच्छित उपयोग dict(**y) पठनीयता उद्देश्यों के लिए dicts बनाने के लिए है, उदाहरण:

dict(a=1, b=10, c=11)

के बजाय

{'a': 1, 'b': 10, 'c': 11}

टिप्पणियों का जवाब

Guido क्या कहता है के बावजूद, dict(x, **y) dict विनिर्देश के साथ लाइन में है, जो बीटीडब्ल्यू। पाइथन 2 और 3 दोनों के लिए काम करता है। तथ्य यह है कि यह केवल स्ट्रिंग कुंजियों के लिए काम करता है, इसका मुख्य परिणाम यह है कि कीवर्ड पैरामीटर कैसे काम करते हैं और न ही कमांड की कमी करते हैं। न ही इस स्थान पर ** ऑपरेटर का उपयोग तंत्र के दुरुपयोग का उपयोग कर रहा है, वास्तव में ** कीवर्ड को कीवर्ड के रूप में सटीक रूप से पास करने के लिए डिज़ाइन किया गया था।

फिर, यह 3 के लिए काम नहीं करता है जब चाबियाँ गैर-तार होती हैं। निहित कॉलिंग अनुबंध यह है कि नेमस्पेस सामान्य डिक्ट्स लेते हैं, जबकि उपयोगकर्ताओं को केवल कीवर्ड तर्कों को पार करना होगा जो तार हैं। अन्य सभी कॉलबल्स ने इसे लागू किया। dict पायथन 2 में इस स्थिरता को तोड़ दिया:

>>> foo(**{('a', 'b'): None})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() keywords must be strings
>>> dict(**{('a', 'b'): None})
{('a', 'b'): None}

पाइथन (पायपी, ज्योथन, आयरनपीथन) के अन्य कार्यान्वयन के कारण यह असंगतता खराब थी। इस प्रकार यह पायथन 3 में तय किया गया था, क्योंकि यह उपयोग एक तोड़ने वाला परिवर्तन हो सकता है।

मैं आपको प्रस्तुत करता हूं कि जानबूझकर कोड लिखने के लिए दुर्भावनापूर्ण अक्षमता है जो केवल एक भाषा के एक संस्करण में काम करती है या केवल कुछ मनमानी बाधाओं को ही काम करती है।

एक और टिप्पणी:

dict(x.items() + y.items()) पाइथन 2 के लिए अभी भी सबसे पठनीय समाधान है। पठनीयता की गणना करता है।

मेरी प्रतिक्रिया: merge_two_dicts(x, y) वास्तव में मुझे बहुत स्पष्ट लगता है, अगर हम वास्तव में पठनीयता के बारे में चिंतित हैं। और यह आगे संगत नहीं है, क्योंकि पाइथन 2 को तेजी से बहिष्कृत किया जा रहा है।

कम प्रदर्शन करने वाला लेकिन सही विज्ञापन-दस्तावेज़

ये दृष्टिकोण कम प्रदर्शनकारी हैं, लेकिन वे सही व्यवहार प्रदान करेंगे। वे होंगे बहुत कम से प्रदर्शन करने वाला copy तथा update या नया अनपॅकिंग क्योंकि वे प्रत्येक कुंजी-मूल्य जोड़ी के माध्यम से अबास्ट्रक्शन के उच्च स्तर पर पुनरावृत्त होते हैं, लेकिन वे कर प्राथमिकता के क्रम का सम्मान करें (बाद के डिकट्स की प्राथमिकता है)

आप एक धैर्य समझ के अंदर मैन्युअल रूप से चित्रों को भी चेन कर सकते हैं:

{k: v for d in dicts for k, v in d.items()} # iteritems in Python 2.7

या पायथन 2.6 में (और शायद जेनरेटर अभिव्यक्तियों को पेश किए जाने पर 2.4 के रूप में):

dict((k, v) for d in dicts for k, v in d.items())

itertools.chain सही क्रम में कुंजी-मूल्य जोड़े पर इटरेटर को चेन करेगा:

import itertools
z = dict(itertools.chain(x.iteritems(), y.iteritems()))

क्षमता का परिक्षण

मैं केवल सही व्यवहार करने के लिए जाने वाले उपयोगों के प्रदर्शन विश्लेषण करने जा रहा हूं।

import timeit

निम्नलिखित उबंटू 14.04 पर किया जाता है

पायथन 2.7 (सिस्टम पायथन) में:

>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.5726828575134277
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.163769006729126
>>> min(timeit.repeat(lambda: dict(itertools.chain(x.iteritems(), y.iteritems()))))
1.1614501476287842
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
2.2345519065856934

पायथन 3.5 में (deadsnakes पीपीए):

>>> min(timeit.repeat(lambda: {**x, **y}))
0.4094954460160807
>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.7881555100320838
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.4525277839857154
>>> min(timeit.repeat(lambda: dict(itertools.chain(x.items(), y.items()))))
2.3143140770262107
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
3.2069112799945287

शब्दकोश पर संसाधन


3352
2017-11-10 22:11





आपके मामले में, आप क्या कर सकते हैं:

z = dict(x.items() + y.items())

यह वही होगा, जैसा कि आप चाहते हैं, अंतिम नियम डालें z, और कुंजी के लिए मूल्य बनाते हैं b दूसरे द्वारा ठीक से ओवरराइड किया जाना चाहिए (y) dict का मूल्य:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = dict(x.items() + y.items())
>>> z
{'a': 1, 'c': 11, 'b': 10}

यदि आप पायथन 3 का उपयोग करते हैं, तो यह केवल थोड़ा और जटिल है। बनाना z:

>>> z = dict(list(x.items()) + list(y.items()))
>>> z
{'a': 1, 'c': 11, 'b': 10}

1440
2017-09-02 07:50





एक विकल्प:

z = x.copy()
z.update(y)

547
2017-09-02 13:00



यह स्पष्ट करने के लिए कि यह प्रश्न द्वारा प्रदान किए गए मानदंड को पूरा क्यों नहीं करता है: यह एक अभिव्यक्ति नहीं है और यह z वापस नहीं करता है। - Alex
@Alex कभी-कभी मूल प्रश्न सही सवाल नहीं है। यदि आपको एक नियमित अभिव्यक्ति के गैर-पायथनिक राक्षस का उपयोग करने की आवश्यकता है, उदाहरण के लिए, एक पंक्ति में कुछ या दो सुन्दर रेखाएं करने के लिए। एक्स करने के लिए, फिर दो लाइनों का उपयोग करें। {**x, **y} स्वीकृत उत्तर में दृष्टिकोण एक monstrosity है। - neuronet
@neuronet प्रत्येक oneliner आमतौर पर सिर्फ कोड चल रहा है जो एक अलग घटक में होना है और इसे हल करता है। यह निश्चित रूप से मामलों में से एक है। लेकिन इसके लिए अन्य भाषाओं में अजगर की तुलना में अच्छे संरचनाएं हैं। और एक संदर्भित रूप से पारदर्शी संस्करण है जो इसके तत्व को लौटाता है, यह बात करना अच्छा होता है। - Alex
इसे इस तरह से रखें: यदि आपको कोड की अपनी एक पंक्ति को उन लोगों को समझाते हुए टिप्पणियों की दो पंक्तियां डालने की आवश्यकता है जिन्हें आप अपना कोड बंद कर देते हैं ... क्या आपने वास्तव में इसे एक पंक्ति में किया है? :) मैं पूरी तरह से सहमत हूं कि पाइथन इसके लिए अच्छा नहीं है: एक बहुत आसान तरीका होना चाहिए। हालांकि यह उत्तर अधिक पाइथनिक है, क्या यह वास्तव में स्पष्ट या स्पष्ट है? Update "कोर" कार्यों में से एक नहीं है जो लोग बहुत उपयोग करते हैं। - neuronet


एक और, संक्षिप्त, विकल्प:

z = dict(x, **y)

ध्यान दें: यह एक लोकप्रिय जवाब बन गया है, लेकिन यह इंगित करना महत्वपूर्ण है कि अगर y इसमें कोई गैर-स्ट्रिंग कुंजी है, तथ्य यह है कि यह एक सीपीथन कार्यान्वयन विस्तार का दुरुपयोग है, और यह पायथन 3, या पीईपीई, आयरनपीथन या ज्योथन में काम नहीं करता है। इसके अलावा, Guido एक प्रशंसक नहीं है। इसलिए मैं इस तकनीक को आगे-संगत या क्रॉस-कार्यान्वयन पोर्टेबल कोड के लिए अनुशंसा नहीं कर सकता, जिसका वास्तव में मतलब है कि इसे पूरी तरह से टालना चाहिए।


273
2017-09-02 15:52





यह शायद एक लोकप्रिय जवाब नहीं होगा, लेकिन आप लगभग निश्चित रूप से ऐसा नहीं करना चाहते हैं। अगर आप एक प्रतिलिपि चाहते हैं जो एक विलय है, तो प्रतिलिपि का उपयोग करें (या deepcopy, जो आप चाहते हैं उसके आधार पर) और फिर अद्यतन करें। कोड की दो पंक्तियां अधिक पढ़ने योग्य हैं - अधिक पायथनिक - .items () + .items () के साथ एकल पंक्ति निर्माण की तुलना में। स्पष्ट से स्पष्ट स्पष्ट है।

इसके अतिरिक्त, जब आप .items () (प्री पायथन 3.0) का उपयोग करते हैं, तो आप एक नई सूची बना रहे हैं जिसमें dict से आइटम शामिल हैं। यदि आपके शब्दकोश बड़े हैं, तो यह काफी अधिक ओवरहेड है (दो बड़ी सूचियां जिन्हें मर्ज किए गए निर्देश के रूप में जल्द ही फेंक दिया जाएगा)। अद्यतन () अधिक कुशलता से काम कर सकता है, क्योंकि यह दूसरे टोक्यो आइटम-बाय-आइटम के माध्यम से चला सकता है।

के अनुसार पहर:

>>> timeit.Timer("dict(x, **y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.52571702003479
>>> timeit.Timer("temp = x.copy()\ntemp.update(y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.694622993469238
>>> timeit.Timer("dict(x.items() + y.items())", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
41.484580039978027

आईएमओ पहले दो के बीच छोटी मंदी पठनीयता के लिए लायक है। इसके अलावा, शब्दकोश निर्माण के लिए कीवर्ड तर्क केवल पायथन 2.3 में जोड़े गए थे, जबकि कॉपी () और अपडेट () पुराने संस्करणों में काम करेंगे।


168
2017-09-08 11:16





फॉलो-अप उत्तर में, आपने इन दो विकल्पों के सापेक्ष प्रदर्शन के बारे में पूछा:

z1 = dict(x.items() + y.items())
z2 = dict(x, **y)

मेरी मशीन पर, कम से कम (एक सामान्य साधारण x86_64 पाइथन 2.5.2 चल रहा है), वैकल्पिक z2 न केवल छोटा और सरल बल्कि काफी तेज़ है। आप इसका उपयोग कर अपने लिए सत्यापित कर सकते हैं timeit मॉड्यूल जो पायथन के साथ आता है।

उदाहरण 1: समान शब्दकोशों में लगातार 20 पूर्णांक मैपिंग:

% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z1=dict(x.items() + y.items())'
100000 loops, best of 3: 5.67 usec per loop
% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z2=dict(x, **y)' 
100000 loops, best of 3: 1.53 usec per loop

z2 3.5 या तो एक कारक से जीतता है। विभिन्न शब्दकोशों में काफी अलग परिणाम मिलते हैं, लेकिन z2 हमेशा आगे आना प्रतीत होता है। (यदि आप के लिए असंगत परिणाम मिलता है वही परीक्षण, में गुजरने का प्रयास करें -r डिफ़ॉल्ट से बड़ी संख्या के साथ 3.)

उदाहरण 2: गैर-ओवरलैपिंग शब्दकोष पूर्णांक के लिए 252 लघु तारों का मानचित्रण करते हैं और इसके विपरीत:

% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z1=dict(x.items() + y.items())'
1000 loops, best of 3: 260 usec per loop
% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z2=dict(x, **y)'               
10000 loops, best of 3: 26.9 usec per loop

z2 10 के एक कारक से जीतता है। यह मेरी किताब में एक बहुत बड़ी जीत है!

उन दोनों की तुलना करने के बाद, मुझे आश्चर्य हुआ कि क्या z1खराब प्रदर्शन को दो आइटम सूचियों के निर्माण के ऊपरी हिस्से को जिम्मेदार ठहराया जा सकता है, जिसने मुझे आश्चर्यचकित कर दिया कि क्या यह बदलाव बेहतर काम कर सकता है:

from itertools import chain
z3 = dict(chain(x.iteritems(), y.iteritems()))

कुछ त्वरित परीक्षण, उदा।

% python -m timeit -s 'from itertools import chain; from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z3=dict(chain(x.iteritems(), y.iteritems()))'
10000 loops, best of 3: 66 usec per loop

मुझे निष्कर्ष निकालने के लिए नेतृत्व करें z3 कुछ हद तक तेज है z1, लेकिन लगभग उतना तेज़ नहीं है z2। निश्चित रूप से सभी अतिरिक्त टाइपिंग के लायक नहीं है।

यह चर्चा अभी भी कुछ महत्वपूर्ण है, जो दो सूचियों को विलय करने के "स्पष्ट" तरीके से इन विकल्पों की प्रदर्शन तुलना है: update तरीका। अभिव्यक्तियों के साथ चीजों को समान पैर पर रखने की कोशिश करने के लिए, जिनमें से कोई भी x या y को संशोधित नहीं करता है, मैं इसे स्थानांतरित करने के बजाय x की प्रतिलिपि बनाने जा रहा हूं, जैसा कि निम्नानुसार है:

z0 = dict(x)
z0.update(y)

एक सामान्य परिणाम:

% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z0=dict(x); z0.update(y)'
10000 loops, best of 3: 26.9 usec per loop

दूसरे शब्दों में, z0 तथा z2 प्रतीत होता है कि अनिवार्य रूप से समान प्रदर्शन है। क्या आपको लगता है कि यह एक संयोग हो सकता है? मैं नही....

असल में, मैं दावा करता हूं कि शुद्ध पायथन कोड के लिए यह असंभव है कि इससे बेहतर कुछ भी हो। और यदि आप सी एक्सटेंशन मॉड्यूल में काफी बेहतर कर सकते हैं, तो मुझे लगता है कि पाइथन लोगों को पाइथन कोर में आपके कोड (या आपके दृष्टिकोण पर भिन्नता) को शामिल करने में रुचि हो सकती है। पायथन का उपयोग करता है dict बहुत सारे स्थानों में; अपने परिचालन को अनुकूलित करना एक बड़ा सौदा है।

आप इसे भी लिख सकते हैं

z0 = x.copy()
z0.update(y)

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


116
2017-10-23 02:38



यह पायथन 3 में काम नहीं करता है; items() समझ में नहीं आता है, और iteritems अस्तित्व में नहीं है। - Antti Haapala


मैं कुछ समान चाहता था, लेकिन यह निर्दिष्ट करने की क्षमता के साथ कि डुप्लिकेट कुंजियों पर मूल्य कैसे विलय किए गए थे, इसलिए मैंने इसे हैक किया (लेकिन इसका परीक्षण नहीं किया)। जाहिर है यह एक अभिव्यक्ति नहीं है, लेकिन यह एक एकल समारोह कॉल है।

def merge(d1, d2, merge_fn=lambda x,y:y):
    """
    Merges two dictionaries, non-destructively, combining 
    values on duplicate keys as defined by the optional merge
    function.  The default behavior replaces the values in d1
    with corresponding values in d2.  (There is no other generally
    applicable merge strategy, but often you'll have homogeneous 
    types in your dicts, so specifying a merge technique can be 
    valuable.)

    Examples:

    >>> d1
    {'a': 1, 'c': 3, 'b': 2}
    >>> merge(d1, d1)
    {'a': 1, 'c': 3, 'b': 2}
    >>> merge(d1, d1, lambda x,y: x+y)
    {'a': 2, 'c': 6, 'b': 4}

    """
    result = dict(d1)
    for k,v in d2.iteritems():
        if k in result:
            result[k] = merge_fn(result[k], v)
        else:
            result[k] = v
    return result

86
2017-09-04 19:08





पायथन 3 में, आप इसका उपयोग कर सकते हैं collections.ChainMap जो एक एकल, अद्यतन करने योग्य दृश्य बनाने के लिए एक साथ कई डाइक या अन्य मैपिंग समूह करता है:

>>> from collections import ChainMap
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = ChainMap({}, y, x)
>>> for k, v in z.items():
        print(k, '-->', v)

a --> 1
b --> 10
c --> 11

73
2018-04-28 03:15



लेकिन चेनमैप का उपयोग करते समय सावधान रहना चाहिए, वहां एक पकड़ है कि यदि आपके पास डुप्लिकेट कुंजी हैं तो पहले मैपिंग के मानों का उपयोग किया जाता है और जब आप कॉल करते हैं del कहें कि एक चेनमैप सी उस कुंजी के पहले मैपिंग को हटा देगा। - Prerit
@Prerit आप इसे और क्या करने की उम्मीद करेंगे? जंजीर नामों का काम सामान्य तरीका है। इस बात पर विचार करें कि $ पैथ बैश में कैसे काम करता है। पथ पर निष्पादन योग्य को हटाने से एक ही नाम के साथ एक और निष्पादन योग्य नहीं होता है। - Raymond Hettinger
@ रेमंड हेटिंगर मैं सहमत हूं, बस एक सावधानी बरत गई। ज्यादातर लोगों को इसके बारे में पता नहीं हो सकता है। : डी - Prerit
मैं सादगी की सिफारिश करने के लिए यहां आया था collections.ChainMap। - hughdbrown
दरअसल, आपके द्वारा यहां प्राप्त किए गए आउटपुट का उपयोग किए बिना भी हासिल किया जा सकता है ChainMap सही? मेरा मतलब है, आपको बस इतना करना है कि बस अपडेट करें z = {**x, **y} और पारंपरिक कदमों का पालन करें, यही वह है! - Steffi Keran Rani J


एक धैर्य को दोबारा अद्यतन / गहरा अद्यतन करें

def deepupdate(original, update):
    """
    Recursively update a dict.
    Subdict's won't be overwritten but also updated.
    """
    for key, value in original.iteritems(): 
        if key not in update:
            update[key] = value
        elif isinstance(value, dict):
            deepupdate(value, update[key]) 
    return update

प्रदर्शन:

pluto_original = {
    'name': 'Pluto',
    'details': {
        'tail': True,
        'color': 'orange'
    }
}

pluto_update = {
    'name': 'Pluutoo',
    'details': {
        'color': 'blue'
    }
}

print deepupdate(pluto_original, pluto_update)

आउटपुट:

{
    'name': 'Pluutoo',
    'details': {
        'color': 'blue',
        'tail': True
    }
}

संपादन के लिए धन्यवाद rednaw।


61
2017-11-29 11:52





कॉपी का उपयोग न करने के दौरान मुझे लगता है कि सबसे अच्छा संस्करण होगा:

from itertools import chain
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
dict(chain(x.iteritems(), y.iteritems()))

यह से तेज है dict(x.items() + y.items()) लेकिन जितना तेज़ नहीं n = copy(a); n.update(b)कम से कम सीपीथन पर। यदि आप बदलते हैं तो यह संस्करण पायथन 3 में भी काम करता है iteritems() सेवा मेरे items(), जो स्वचालित रूप से 2to3 उपकरण द्वारा किया जाता है।

व्यक्तिगत रूप से मुझे यह संस्करण सबसे अच्छा लगता है क्योंकि यह एक ही कार्यात्मक वाक्यविन्यास में जो कुछ भी चाहता है वह काफी अच्छा वर्णन करता है। एकमात्र मामूली समस्या यह है कि यह पूरी तरह से स्पष्ट नहीं करता है कि y से मानों को x से मानों पर प्राथमिकता मिलती है, लेकिन मुझे विश्वास नहीं है कि इसे समझना मुश्किल है।


54
2017-10-14 18:55





पायथन 3.5 (पीईपी 448) एक अच्छा सिंटैक्स विकल्प की अनुमति देता है:

x = {'a': 1, 'b': 1}
y = {'a': 2, 'c': 2}
final = {**x, **y} 
final
# {'a': 2, 'b': 1, 'c': 2}

या और भी

final = {'a': 1, 'b': 1, **x, **y}

41
2018-02-26 21:27



इस समाधान से बेहतर तरीके से क्या है dict(x, **y)-उपाय? जैसा कि आप (@ करलमेयर) ने आपके अपने उत्तर के नोट के भीतर उल्लेख किया है (stackoverflow.com/a/39858/2798610) Guido उस समाधान पर विचार करता है अवैध। - Blackeagle52
Guido नापसंद dict(x, **y) (बहुत अच्छा) कारण है कि यह निर्भर करता है y केवल कुंजी होने वाली वैध कीवर्ड तर्क नाम हैं (जब तक आप CPython 2.7 का उपयोग नहीं कर रहे हैं, जहां dict constructor धोखा देती है)। यह आपत्ति / प्रतिबंध पीईपी 448 पर लागू नहीं होता है, जो सामान्यीकृत करता है ** तेंदुए के लिए वाक्यविन्यास unpacking। तो इस समाधान के समान संयोजन है dict(x, **y), नकारात्मक के बिना। - Carl Meyer