मैं एक ही अभिव्यक्ति में दो पायथन शब्दकोशों का विलय कैसे कर सकता हूं?
शब्दकोशों के लिए x
और y
, उन लोगों की जगह z
से मूल्यों के साथ एक उथले विलय शब्दकोष बन जाता है ।y
x
पायथन 3.5 या अधिक में:
z = {**x, **y}
पायथन 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)
पायथन में 3.9.0a4 या उससे अधिक (अंतिम रिलीज की तारीख लगभग अक्टूबर 2020): PEP-584 , यहां चर्चा की गई , इसे और सरल बनाने के लिए लागू किया गया:
z = x | y # NOTE: 3.9+ ONLY
व्याख्या
मान लें कि आपके पास दो डाइक हैं और आप मूल डाइक को बदले बिना उन्हें एक नए अधिमान में विलय करना चाहते हैं:
x = {'a': 1, 'b': 2}
y = {'b': 3, 'c': 4}
वांछित परिणाम z
विलय के साथ एक नया शब्दकोश ( ) प्राप्त करने के लिए है , और पहले से उन पर ओवरराइटिंग करने वाले दूसरे तानाशाह के मूल्य हैं।
>>> z
{'a': 1, 'b': 3, 'c': 4}
इसके लिए एक नया वाक्यविन्यास, पीईपी 448 में प्रस्तावित और पायथन 3.5 के रूप में उपलब्ध है
z = {**x, **y}
और यह वास्तव में एक ही अभिव्यक्ति है।
ध्यान दें कि हम शाब्दिक अंकन के साथ भी विलय कर सकते हैं:
z = {**x, 'foo': 1, 'bar': 2, **y}
और अब:
>>> z
{'a': 1, 'b': 3, 'foo': 1, 'bar': 2, 'c': 4}
अब इसे 3.5, PEP 478 के रिलीज़ शेड्यूल में लागू किया जा रहा है , और इसने अब Python 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 में काम करेगा। दिए गए dicts जैसे 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 में उपयोग किए जा रहे उपयोग का एक उदाहरण है ।
डायट्स को हेज़ल कीज़ (जैसे फ्रोज़ेनसेट्स या ट्यूपल्स) लेने का इरादा है, लेकिन पाइथन 3 में यह विधि विफल हो जाती है जब चाबियाँ स्ट्रिंग्स नहीं होती हैं।
>>> c = dict(a, **b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings
से मेलिंग सूची , गुइडो van Rossum, भाषा के निर्माता ने लिखा है:
मैं तानाशाह ({}, ** {1: 3}) को अवैध घोषित करने के साथ ठीक हूं, क्योंकि आखिरकार यह ** तंत्र का दुरुपयोग है।
तथा
जाहिर तौर पर तानाशाही (x, ** y) "कॉल x.update (y) और रिटर्न x" के लिए "कूल हैक" के रूप में घूम रहा है। व्यक्तिगत रूप से मैं इसे शांत से अधिक तुच्छ समझता हूं।
यह मेरी समझ है (साथ ही भाषा के निर्माता की समझ ) कि dict(**y)
पठनीय उद्देश्यों के लिए डिकेट बनाने के लिए इसका उपयोग करना है, जैसे:
dict(a=1, b=10, c=11)
के बजाय
{'a': 1, 'b': 10, 'c': 11}
टिप्पणियों का जवाब
गुइडो जो कहते हैं, उसके बावजूद, dict(x, **y)
यह विशिष्ट विनिर्देश के अनुरूप है, जो कि btw। पायथन 2 और 3 दोनों के लिए काम करता है। यह तथ्य कि यह केवल स्ट्रिंग कीज़ के लिए काम करता है, इसका एक प्रत्यक्ष परिणाम है कि कीवर्ड पैरामीटर कैसे काम करते हैं और तानाशाही की कमी नहीं है। न ही ** ऑपरेटर का उपयोग इस जगह में तंत्र का दुरुपयोग है, वास्तव में ** को कीवर्ड के रूप में dicts पास करने के लिए डिज़ाइन किया गया था।
फिर, यह 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}
इस असंगति को पायथन (Pypy, Jython, IronPython) के अन्य कार्यान्वयनों को देखते हुए बुरा माना गया। इस प्रकार यह पायथन 3 में तय किया गया था, क्योंकि यह उपयोग एक ब्रेकिंग परिवर्तन हो सकता है।
मैं आपके सामने प्रस्तुत करता हूं कि यह जानबूझकर कोड लिखने के लिए दुर्भावनापूर्ण अक्षमता है जो केवल एक भाषा के एक संस्करण में काम करता है या केवल कुछ मनमाने बाधाओं को देखते हुए काम करता है।
अधिक टिप्पणियाँ:
dict(x.items() + y.items())
अभी भी पायथन 2 के लिए सबसे पठनीय समाधान है। पठनीयता मायने रखती है।
मेरी प्रतिक्रिया: merge_two_dicts(x, y)
वास्तव में मुझे बहुत स्पष्ट लगता है, अगर हम वास्तव में पठनीयता के बारे में चिंतित हैं। और यह आगे संगत नहीं है, क्योंकि पायथन 2 तेजी से पदावनत है।
{**x, **y}
नेस्टेड शब्दकोशों को संभालने के लिए प्रतीत नहीं होता है। नेस्टेड कुंजियों की सामग्री को केवल ओवरराइट किया जाता है, विलय नहीं किया जाता है [...] मैं समाप्त हो गया इन उत्तरों द्वारा जलाया जा रहा है जो पुनरावृत्ति में विलय नहीं करते हैं और मुझे आश्चर्य हुआ कि किसी ने भी इसका उल्लेख नहीं किया। शब्द "मर्जिंग" की मेरी व्याख्या में इन उत्तरों का वर्णन है "एक दूसरे के साथ तानाशाही को अद्यतन करना", और विलय नहीं।
हाँ। मुझे आपको उस प्रश्न का वापस उल्लेख करना चाहिए, जो दो शब्दकोशों के उथले विलय के लिए पूछ रहा है , पहले मूल्यों को दूसरे के द्वारा एक ही अभिव्यक्ति में अधिलेखित किया जा रहा है।
शब्दकोशों के दो शब्दकोश मानते हुए, कोई भी उन्हें एक ही फ़ंक्शन में पुन: विलय कर सकता है, लेकिन आपको सावधान रहना चाहिए कि किसी भी स्रोत से डाइक को संशोधित न करें, और इससे बचने का सबसे सुरक्षित तरीका है कि मूल्यों को असाइन करते समय एक प्रतिलिपि बनाएं। चूंकि चाबियां हवादार होनी चाहिए और आमतौर पर अपरिवर्तनीय होती हैं, इसलिए उन्हें कॉपी करना व्यर्थ है:
from copy import deepcopy
def dict_of_dicts_merge(x, y):
z = {}
overlapping_keys = x.keys() & y.keys()
for key in overlapping_keys:
z[key] = dict_of_dicts_merge(x[key], y[key])
for key in x.keys() - overlapping_keys:
z[key] = deepcopy(x[key])
for key in y.keys() - overlapping_keys:
z[key] = deepcopy(y[key])
return z
उपयोग:
>>> x = {'a':{1:{}}, 'b': {2:{}}}
>>> y = {'b':{10:{}}, 'c': {11:{}}}
>>> dict_of_dicts_merge(x, y)
{'b': {2: {}, 10: {}}, 'a': {1: {}}, 'c': {11: {}}}
अन्य मूल्य प्रकारों के लिए आकस्मिकताओं के साथ आना इस प्रश्न के दायरे से परे है, इसलिए मैं आपको "शब्दकोशों के विलय के शब्दकोश" पर कैनोनिकल प्रश्न के उत्तर में बताऊंगा ।
कम कलाकार लेकिन सही विज्ञापन-होक्स
ये दृष्टिकोण कम प्रदर्शन वाले हैं, लेकिन वे सही व्यवहार प्रदान करेंगे। वे हो जाएगा बहुत कम की तुलना में performant copy
और update
या नए unpacking क्योंकि वे अमूर्त की एक उच्च स्तर पर प्रत्येक कुंजी-मान पेयर के माध्यम से पुनरावृति है, लेकिन वे करते हैं (उत्तरार्द्ध dicts पूर्वता है) प्राथमिकता का क्रम का सम्मान
तुम भी एक तानाशाही समझ के अंदर मैन्युअल रूप से dicts श्रृंखला कर सकते हैं:
{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()))
क्षमता का परिक्षण
मैं केवल सही ढंग से व्यवहार करने के लिए ज्ञात usages के प्रदर्शन विश्लेषण करने जा रहा हूँ।
import timeit
निम्नलिखित Ubuntu 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 में (पीपीए के बारे में जानकारी):
>>> 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
शब्दकोश पर संसाधन
z = x | y