2009-09-21 20 views
87

मैं ऐसा करने की कोशिश कर रहा 'एम:क्यों एक अजगर dict.update() वस्तु वापस नहीं करता है?

award_dict = { 
    "url" : "http://facebook.com", 
    "imageurl" : "http://farm4.static.flickr.com/3431/3939267074_feb9eb19b1_o.png", 
    "count" : 1, 
} 

def award(name, count, points, desc_string, my_size, parent) : 
    if my_size > count : 
     a = { 
      "name" : name, 
      "description" : desc_string % count, 
      "points" : points, 
      "parent_award" : parent, 
     } 
     a.update(award_dict) 
     return self.add_award(a, siteAlias, alias).award 

लेकिन अगर वास्तव में समारोह में बोझिल महसूस किया है, और मैं नहीं बल्कि किया होता:

 return self.add_award({ 
      "name" : name, 
      "description" : desc_string % count, 
      "points" : points, 
      "parent_award" : parent, 
     }.update(award_dict), siteAlias, alias).award 

वस्तु लौट तो आप कर सकते हैं क्यों अपडेट नहीं करता जंजीर?

JQuery यह करने के लिए यह करता है। पाइथन में यह स्वीकार्य क्यों नहीं है?

उत्तर

154

पायथन के ज्यादातर command-query separation का एक व्यावहारिक रंग स्वाद को लागू करने: mutators लौट None (जैसे pop के रूप में व्यावहारिक प्रेरित अपवाद ;-) तो वे संभवतः accessors के साथ भ्रमित नहीं किया जा सकता है के साथ (और एक ही नस में, काम नहीं एक अभिव्यक्ति है , बयान-अभिव्यक्ति अलगाव वहाँ है, और बहुत आगे)।

इसका मतलब यह नहीं है कि जब आप वास्तव में चाहते हैं तो चीजों को मर्ज करने के कई तरीके नहीं हैं, उदाहरण के लिए, dict(a, **award_dict).update लौटने की इच्छा के समान एक नया निर्देश बनाता है - तो इसका उपयोग क्यों न करें अगर आपको वास्तव में यह महत्वपूर्ण लगता है?

संपादित: Btw, कोई जरूरत नहीं, अपने विशिष्ट मामले में, a रास्ते बनाने के लिए, या तो:

dict(name=name, description=desc % count, points=points, parent_award=parent, 
    **award_dict) 

, वास्तव में अपने a.update(award_dict) (सहित के रूप में ही अर्थ विज्ञान के साथ एक एकल dict बनाता में संघर्ष के मामले में, तथ्य यह है कि award_dict में प्रविष्टियों उन आप स्पष्ट रूप से दे रहे हैं ओवरराइड; से पहले अन्य अर्थ विज्ञान प्राप्त करने के लिए, यानी, स्पष्ट प्रविष्टियों "विजेता" ऐसे संघर्षों के लिए, award_dict एकमात्र स्थितीय आर्ग के रूप में पारित, ke yword वाले, और ** रूप से बेरफेट - dict(award_dict, name=name इत्यादि)।

+0

ठीक है, यह एक और शब्दकोश बनाने के बाद मुझे बनाना होगा। मैं एक नियम बनाना चाहता था, और फिर अन्य मूल्यों का एक समूह जोड़ना चाहता था, और फिर इसे एक समारोह में देना। –

+0

@ पॉल, और यह वही है जो आप कर रहे हैं - दो कथनों के साथ (जो नेस्टेड तरीके से आप चाहते थे उससे ज्यादा पठनीय) जो आपको "वास्तव में बोझिल महसूस किया"। यह दिखाने के लिए मेरा जवाब संपादित करना कि 'ए' को पूरी तरह से बनाने से कैसे बचें, btw, –

+12

'dict (a, ** award_dict) 'बस चट्टानों और वही था जो मैं चाहता था-इसके लिए धन्यवाद! ('dict (d1.items() + d2 का उपयोग कर रहा था।आइटम()) 'पहले) –

3

ऐसा नहीं है कि यह स्वीकार्य नहीं है, बल्कि dicts इस तरह लागू नहीं किया गया था।

यदि आप Django के ORM को देखते हैं, तो यह चेनिंग का व्यापक उपयोग करता है। यह निराश नहीं है, आप dict से भी उत्तराधिकारी हो सकते हैं और यदि आप वास्तव में चाहते हैं तो return self अपडेट करने के लिए केवल update ओवरराइड करें।

class myDict(dict): 
    def update(self, *args): 
     dict.update(self, *args) 
     return self 
+0

धन्यवाद, यह पैच को पैच कर सकता है, मैं सिर्फ यह जानना चाहता था कि क्यों dict() ने इस कार्यक्षमता को स्वयं अनुमति नहीं दी है (क्योंकि यह उतना आसान है जितना आप प्रदर्शित करते हैं)। क्या Django पैच इस तरह से निर्देशित करता है? –

28

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

ऐसा करने के लिए प्रेरणा यह है कि अन्यथा, आपको अवांछित दुष्प्रभाव मिल सकते हैं। पर विचार करें

bar = foo.reverse() 

रिवर्स (जो यथा-स्थान सूची पराजयों) भी सूची वापसी होगी, तो उपयोगकर्ता सोच सकते हैं कि रिवर्स एक नई सूची जो बार सौंप दिया जाता है देता है, और कहा कि foo भी संशोधित हो जाता है नोटिस कभी नहीं। रिवर्स रिटर्न करके कोई भी नहीं, वे तुरंत पहचानते हैं कि बार उलटा होने का नतीजा नहीं है, और रिवर्स का असर क्या होगा और अधिक करीब दिखाई देगा।

+1

धन्यवाद। टी रिवर्स भी इसे जगह में नहीं करने का विकल्प देता है? प्रदर्शन? 'रिवर्स (foo)' अजीब लगता है। –

+0

जोड़ना एक विकल्प अनुचित होगा: यह पैरामीटर के आधार पर विधि की प्रकृति को बदल देगा। हालांकि, विधियों को वास्तव में निश्चित प्रकार के प्रकार निर्धारित करना चाहिए (दुर्भाग्य से, ऐसे मामले जहां यह नियम टूटा हुआ है)। एक प्रतिलिपि प्रतिलिपि बनाना आसान है: बस एक प्रति बनाएं ('bar = foo [:]' का उपयोग करके), फिर प्रतिलिपि वापस करें। –

+2

मुझे लगता है कि कारण स्पष्ट है। 'Bar = foo.reverse() 'में, आप सोच सकते हैं कि' foo' संशोधित नहीं है। भ्रम से बचने के लिए, आपके पास 'foo.reverse()' और 'bar = reversed (foo)' दोनों हैं। –

9
>>> dict_merge = lambda a,b: a.update(b) or a 
>>> dict_merge({'a':1, 'b':3},{'c':5}) 
{'a': 1, 'c': 5, 'b': 3} 

ध्यान दें कि विलय किए गए निर्देश को वापस करने के साथ-साथ यह पहले पैरामीटर को जगह में संशोधित करता है। तो dict_merge (ए, बी) एक संशोधित करेगा।

या, निश्चित रूप से, आप यह सब इनलाइन कर सकते हैं:

>>> (lambda a,b: a.update(b) or a)({'a':1, 'b':3},{'c':5}) 
{'a': 1, 'c': 5, 'b': 3} 
+8

-1 'लैम्ब्डा' का उपयोग इस तरह नहीं किया जाना चाहिए, इसके बजाय परंपरागत फ़ंक्शन 'def' का उपयोग करें – jamylak

+2

को लैम्ब्डा की भी आवश्यकता नहीं है, बस' a.update (b) या a' का उपयोग करें – Pycz

0
import itertools 
dict_merge = lambda *args: dict(itertools.chain(*[d.iteritems() for d in args])) 
3

टिप्पणी के लिए पर्याप्त नहीं प्रतिष्ठा शीर्ष जवाब पर छोड़ दिया

इस @beardc होना प्रतीत नहीं होता है सीपीथन चीज। PyPy देता है मुझे "लेखन त्रुटि: कीवर्ड तार होना चाहिए"

**kwargs साथ समाधान ही काम करता है क्योंकि शब्दकोश केवल मर्ज करने प्रकार स्ट्रिंग की कुंजी है।

यानी

>>> dict({1:2}, **{3:4}) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: keyword arguments must be strings 

बनाम

>>> dict({1:2}, **{'3':4}) 
{1: 2, '3': 4} 
1

के रूप में अपने प्रस्तावित समाधान के करीब के रूप में मैं मिल सकता है

from collections import ChainMap 

return self.add_award(ChainMap(award_dict, { 
    "name" : name, 
    "description" : desc_string % count, 
    "points" : points, 
    "parent_award" : parent, 
}), siteAlias, alias).award 
0

बस अजगर 3.4 में यह अपने आप कोशिश कर रहा (ऐसा नहीं था फैंसी {**dict_1, **dict_2} वाक्यविन्यास का उपयोग करने में सक्षम)।

मैं शब्दकोशों में गैर-स्ट्रिंग कुंजी रखने के साथ-साथ शब्दकोशों की मनमानी मात्रा प्रदान करने में सक्षम होना चाहता था।

इसके अलावा, मैं तो मैं collections.ChainMap (थोड़े कारण का उपयोग नहीं करने के लिए मैं शुरू में dict.update उपयोग करने के लिए नहीं करना चाहता था का विकल्प चुना एक नया शब्दकोश बनाना चाहते थे

यहाँ है कि मैं क्या लेखन समाप्त हो गया है:।

def merge_dicts(*dicts): 
    all_keys = set(k for d in dicts for k in d.keys()) 
    chain_map = ChainMap(*reversed(dicts)) 
    return {k: chain_map[k] for k in all_keys} 

merge_maps({'1': 1}, {'2': 2, '3': 3}, {'1': 4, '3': 5}) 
# {'1': 4, '3': 5, '2': 2} 
संबंधित मुद्दे