एक अजगर तानाशाही क्यों नहीं करता है।


139

मैं करने की कोशिश कर रहा हूँ:

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 ऐसा करने के लिए करता है। यह अजगर में स्वीकार्य क्यों नहीं है?


14
* टीएल; डीआरnewdict = dict(dict001, **dict002)
डेफटर्मैक

2
@dreftymac, हालांकि समझ में नहीं आता है।
अलंकालविटि १३'१

@alancalvitti हां, यह वास्तव में इंगित करने के लिए एक वैध चेतावनी है।
dreftymac

जवाबों:


219

पायथन का ज्यादातर कमांड-क्वेरी पृथक्करण का व्यावहारिक रूप से थका हुआ स्वाद लागू करना है : उत्परिवर्ती वापसी None(व्यावहारिक रूप से प्रेरित अपवाद जैसे pop;;; इसलिए वे संभवतः एक्सेसर्स के साथ भ्रमित नहीं हो सकते हैं (और एक ही नस में, असाइनमेंट एक अभिव्यक्ति नहीं है, कथन) - एक्सप्रेशन पृथक्करण है, और इसके आगे)।

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

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

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

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


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

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

1
मूल समाधान मजबूत नहीं है। यदि अवार्ड_डिक्ट में पहले से निर्दिष्ट कुंजियाँ हैं, तो दोहराया कीवर्ड तर्क के लिए एक SyntaxError फेंक दिया जाएगा। जैमाइलक का समाधान तानाशाही (itertools.chain (d1.iteritems) (, .. d <n> .iteritems ())) न केवल उस मामले में काम करता है, जहाँ शब्दकोशों में डुप्लिकेट कुंजियाँ होती हैं, लेकिन आसानी से आप बाद में dicts के साथ कई शब्दकोश मर्ज कर सकते हैं। अंतिम मूल्य के लिए पूर्वता लेने वाली श्रृंखला।
मैट

2
इसके अलावा, अगर अवार्ड_डिक्ट में कीज़ स्ट्रिंग नहीं हैं तो दुभाषिया एकTypeError
कुँएल

3
dict(old_dict, old_key=new_value)कीवर्ड के लिए कई मान नहीं फेंकेंगे और नया तानाशाही नहीं करेंगे।
चार्मी

35

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

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

bar = foo.reverse()

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


1
धन्यवाद। रिवर्स भी क्यों नहीं विकल्प यह नहीं करेंगे? प्रदर्शन? कर reverse(foo)अजीब लगता है।
पॉल टारजन

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

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

एक पैरामीटर के आधार पर पैरामीटर की प्रकृति को बदलने में क्या गलत है?
जुलिएन


15
>>> 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 (a, b) संशोधित करेगा a।

या, ज़ाहिर है, आप इसे सभी इनलाइन कर सकते हैं:

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

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

8
यहां तक ​​कि एक a.update(b) or a
मेमने

10

शीर्ष उत्तर पर टिप्पणी के लिए पर्याप्त प्रतिष्ठा नहीं बची

@beardc यह CPython बात नहीं लगती। PyPy मुझे "TypeError: कीवर्ड स्ट्रिंग्स होना चाहिए"

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

5

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

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

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

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

2

अपने प्रस्तावित समाधान के करीब जितना मैं पा सकता था

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

1

पार्टी में देर से आने वालों के लिए, मैंने कुछ समय एक साथ रखा था (Py 3.7), यह दिखाते हुए कि .update()आधारित तरीके थोड़े (~ 5%) तेज़ी से दिखते हैं, जब इनपुट संरक्षित होते हैं और नोटिकली (~ 30%) तेजी से, जब बस इन-प्लेस अपडेट करते हैं ।

हमेशा की तरह, सभी बेंचमार्क को नमक के दाने के साथ लेना चाहिए।

def join2(dict1, dict2, inplace=False):
    result = dict1 if inplace else dict1.copy()
    result.update(dict2)
    return result


def join(*items):
    iter_items = iter(items)
    result = next(iter_items).copy()
    for item in iter_items:
        result.update(item)
    return result


def update_or(dict1, dict2):
    return dict1.update(dict2) or dict1


d1 = {i: str(i) for i in range(1000000)}
d2 = {str(i): i for i in range(1000000)}

%timeit join2(d1, d2)
# 258 ms ± 1.47 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit join(d1, d2)
# 262 ms ± 2.97 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit dict(d1, **d2)
# 267 ms ± 2.74 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit {**d1, **d2}
# 267 ms ± 1.84 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

इन-प्लेस ऑपरेशन के लिए समय थोड़ा पेचीदा होता है, इसलिए इसे एक अतिरिक्त कॉपी ऑपरेशन (पहली टाइमिंग केवल संदर्भ के लिए) के साथ संशोधित करना होगा:

%timeit dd = d1.copy()
# 44.9 ms ± 495 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit dd = d1.copy(); join2(dd, d2)
# 296 ms ± 2.05 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit dd = d1.copy(); join2(dd, d2, True)
# 234 ms ± 1.02 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit dd = d1.copy(); update_or(dd, d2)
# 235 ms ± 1.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

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

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}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.