विनाशकारी-बाँध शब्दकोश सामग्री


85

मैं एक शब्दकोश को नष्ट करने की कोशिश कर रहा हूं और इसकी कुंजी के बाद चर नामों के साथ मूल्यों को संबद्ध करता हूं। कुछ इस तरह

params = {'a':1,'b':2}
a,b = params.values()

लेकिन चूंकि शब्दकोशों का आदेश नहीं दिया जाता है, इसलिए कोई गारंटी नहीं है कि params.values()मूल्यों के क्रम में वापस आ जाएगा (a, b)। क्या ऐसा करने का एक अच्छा तरीका है?


3
आलसी? हो सकता है ... लेकिन निश्चित रूप से मैंने दृष्टांत के लिए सबसे सरल मामला दिखाया है। आदर्श रूप में मैं x के लिए params.items में पसंद करना चाहता था: eval ('% s =% f'% x) लेकिन मुझे लगता है कि eval () असाइनमेंट की अनुमति नहीं देता है।
हैमेट्रिक्स

7
@JochenRitzel मुझे पूरा यकीन है कि ES6 (जावास्क्रिप्ट) के अधिकांश उपयोगकर्ता नई वस्तु विनाशकारी वाक्य रचना पसंद करते हैं let {a, b} = params:। यह पठनीयता को बढ़ाता है और आप जिस भी ज़ेन के बारे में बात करना चाहते हैं, उसके साथ पूरी तरह से इनलाइन है।
एंडी

8
@ और मुझे जेएस में विनाशकारी वस्तु पसंद है । एक तानाशाही से कुछ चाबियाँ निकालने के लिए एक साफ, सरल और पठनीय तरीका क्या है। मैं पायथन में कुछ इसी तरह की खोज की उम्मीद के साथ आया था।
रोटारेटी

2
मुझे ES6 ऑब्जेक्ट विनाशकारी भी पसंद है, लेकिन मुझे डर है कि यह Python में उसी कारण से काम नहीं कर सकता है जब ES6 का मैप ऑब्जेक्ट विनाशकारी का समर्थन नहीं करता है। कुंजी केवल ES6 मैप और पाइथन तानाशाही में तार नहीं हैं। इसके अलावा, हालांकि मुझे ES6 में ऑब्जेक्ट डिस्ट्रक्टिंग की "प्लक" शैली पसंद है, असाइनमेंट स्टाइल सरल नहीं है। यहाँ क्या चल रहा है? let {a: waffles} = params। यह पता लगाने में कुछ सेकंड लगते हैं, भले ही आप इसका उपयोग कर रहे हों।
जॉन क्रिस्टोफर जोन्स

1
@ naught101 व्यापार की स्थिति के लिए आश्चर्यजनक रूप से उपयोगी है। उपयोगकर्ताओं के लिए: पायथन में कोई भी वस्तु अपने स्वयं के str / repr तरीके प्रदान कर सकती है। यह भी आसान JSON क्रमांकन के लिए थोड़ा जटिल प्रमुख वस्तुओं (जैसे, टुपल्स नाम) के लिए ऐसा करने के लिए आकर्षक हो सकता है। अब आप अपना सिर खुजला रहे हैं कि आप नाम से चाबी क्यों नहीं नष्ट कर सकते। इसके अलावा, यह आइटमों के लिए क्यों काम करता है, लेकिन एट्र्स नहीं? पुस्तकालयों के बहुत सारे लोग पसंद करते हैं। कार्यान्वयनकर्ताओं के लिए, यह ES6 फीचर प्रतीकों (बाइंडेबल नामों) और स्ट्रिंग्स को भ्रमित करता है: जावास्क्रिप्ट में उचित है लेकिन पायथन के पास खेलने में बहुत समृद्ध विचार हैं। इसके अलावा, यह सिर्फ बदसूरत दिखेगा।
जॉन क्रिस्टोफर जोन्स

जवाबों:


10

यदि आप स्थानीय शब्दकोश के उपयोग से जुड़े मुद्दों से डरते हैं और आप अपनी मूल रणनीति का पालन करना पसंद करते हैं, तो ऑर्डर किए गए शब्दकोश python 2.7 और 3.1 संग्रह से। ऑर्डर किए गए दस्तावेज़ आपको उस क्रम में शब्दकोश आइटम पुनर्प्राप्त करने की अनुमति देते हैं जिसमें वे पहले सम्मिलित किए गए थे।


@ स्टेफेन आप भाग्यशाली हैं क्योंकि ऑर्डरेडडिक्ट्स को अजगर 3.1 से अजगर 2.7 तक चित्रित किया गया है
16

मैं इसकी आशा करता हूं...! सोचा कि मेरे लिए हमेशा पायथन के लिए एक स्टिकिंग पॉइंट था (कि ऑर्डर किए गए डिक्शनरी दूसरी बैटरी के साथ लोड नहीं हुई)
हैमेट्रिक्स

4
वर्तमान में, 3.5+ में, सभी शब्दकोशों का आदेश दिया जाता है। यह अभी तक "गारंटीकृत" नहीं है, जिसका अर्थ है कि यह बदल सकता है।
चार्ल्स मरियम

4
इसकी गारंटी 3.6+ से है।
naught101

122
from operator import itemgetter

params = {'a': 1, 'b': 2}

a, b = itemgetter('a', 'b')(params)

विस्तृत लांबा कार्यों या शब्दकोश की समझ के बजाय, एक पुस्तकालय में निर्मित उपयोग कर सकते हैं।


9
यह संभवतः स्वीकृत उत्तर होना चाहिए, क्योंकि यह इसे करने का सबसे पाइथोनिक तरीका है। आप attrgetterसमान मानक लाइब्रेरी मॉड्यूल से उपयोग करने के उत्तर का विस्तार भी कर सकते हैं , जो ऑब्जेक्ट विशेषताओं ( obj.a) के लिए काम करता है । यह जावास्क्रिप्ट से एक बड़ा अंतर है, जहां obj.a === obj["a"]
जॉन क्रिस्टोफर जोन्स

यदि शब्दकोष में कुंजी मौजूद नहीं है तो KeyErrorअपवाद को उठाया जाएगा
तस्वर हुसैन

2
लेकिन आप विनाशकारी बयान में दो बार एक और बी टाइप कर रहे हैं
ओटो

1
@JohnChristopherJones जो मुझे बहुत स्वाभाविक नहीं लगता, मौजूदा सामान का उपयोग करने का मतलब यह नहीं है कि यह समझ में आता है। मुझे संदेह है कि कई लोग तुरंत एक वास्तविक कोड में समझ जाएंगे। दूसरी ओर, जैसा कि सुझाव दिया गया है a, b = [d[k] for k in ('a','b')]कि रास्ता अधिक प्राकृतिक / पठनीय है (फॉर्म अधिक सामान्य है)। यह अभी भी एक दिलचस्प जवाब है, लेकिन यह सबसे सीधा समाधान नहीं है।
cglacet

@ मुझे लगता है कि यह इस बात पर निर्भर करता है कि आपको इसे कितनी बार पढ़ना / लागू करना है। यदि आप नियमित रूप से उन्हीं 3 कुंजियों को चुनते हैं, get_id = itemgetter(KEYS)तो बाद में उपयोग serial, code, ts = get_id(document)करना सरल होता है। बेशक, आपको उच्च-क्रम वाले कार्यों के साथ सहज होना होगा, लेकिन पायथन आमतौर पर उनके साथ बहुत सहज है। जैसे, सज्जाकार के लिए डॉक्स देखें @contextmanager
जॉन क्रिस्टोफर जोन्स

29

जोचेन के सुझाव की तुलना में कम पुनरावृत्ति के साथ ऐसा करने का एक तरीका सहायक कार्य के साथ है। यह आपके चर नामों को किसी भी क्रम में सूचीबद्ध करने का लचीलापन देता है और केवल उस चीज़ के एक उप-भाग को नष्ट करता है जो तानाशाह में है:

pluck = lambda dict, *args: (dict[arg] for arg in args)

things = {'blah': 'bleh', 'foo': 'bar'}
foo, blah = pluck(things, 'foo', 'blah')

इसके अलावा, जौक्विन के ऑर्डरडीड के बजाय आप चाबियाँ सॉर्ट कर सकते हैं और मान प्राप्त कर सकते हैं। एकमात्र कैच आपको अपने वर्णमाला के नाम को वर्णानुक्रम में निर्दिष्ट करने और सभी चीज़ों को नष्ट करने की आवश्यकता है:

sorted_vals = lambda dict: (t[1] for t in sorted(dict.items()))

things = {'foo': 'bar', 'blah': 'bleh'}
blah, foo = sorted_vals(things)

4
यह एक छोटी सी वक्रोक्ति है, लेकिन यदि आप lambdaएक चर को असाइन करने जा रहे हैं, तो आप सामान्य फ़ंक्शन सिंटैक्स का भी उपयोग कर सकते हैं def
आर्थर टाका

अभिलिखित कठबोली आप इसे जेएस की तरह करते हैं जहां यह कॉन्स्ट {a, b} = {a: 1, b: 2}
PirateApp

1
आपने मानक पुस्तकालय itemgetterसे कार्यान्वित किया operatorहै। :)
जॉन क्रिस्टोफर जोन्स

17

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

a,b = [d[k] for k in ('a','b')]

यह जनरेटर के साथ भी काम करता है:

a,b = (d[k] for k in ('a','b'))

यहाँ एक पूर्ण उदाहरण है:

>>> d = dict(a=1,b=2,c=3)
>>> d
{'a': 1, 'c': 3, 'b': 2}
>>> a, b = [d[k] for k in ('a','b')]
>>> a
1
>>> b
2
>>> a, b = (d[k] for k in ('a','b'))
>>> a
1
>>> b
2

10

शायद आप वास्तव में ऐसा कुछ करना चाहते हैं?

def some_func(a, b):
  print a,b

params = {'a':1,'b':2}

some_func(**params) # equiv to some_func(a=1, b=2)

धन्यवाद, लेकिन ऐसा नहीं है ... मैं एक समारोह के भीतर विनाशकारी हूँ
हैमेट्रिक्स

10

जेएस में एक विनाशकारी असाइनमेंट कैसे काम करता है, यह इसी तरह से करने का एक और तरीका है :

params = {'b': 2, 'a': 1}
a, b, rest = (lambda a, b, **rest: (a, b, rest))(**params)

हमने जो किया वह परम शब्दकोश को प्रमुख मूल्यों (** का उपयोग करके) में अनपैक करने के लिए था (जैसे जोचन के उत्तर में ), फिर हमने लैम्बडा हस्ताक्षर में उन मानों को लिया है और उन्हें प्रमुख नाम के अनुसार नियत किया है - और यहाँ एक बोनस है - हम लैम्ब्डा के हस्ताक्षर में जो कुछ भी नहीं है उसका एक शब्दकोश भी प्राप्त करें ताकि यदि आपके पास था:

params = {'b': 2, 'a': 1, 'c': 3}
a, b, rest = (lambda a, b, **rest: (a, b, rest))(**params)

लैम्ब्डा लागू होने के बाद, बाकी चर अब शामिल होंगे: {'c': 3}

एक शब्दकोश से अनावश्यक चाबियाँ छोड़ने के लिए उपयोगी है।

उम्मीद है की यह मदद करेगा।


दिलचस्प है, दूसरी तरफ मुझे लगता है कि यह एक समारोह में बेहतर होगा। आप शायद कई बार इसका उपयोग करेंगे और इस तरह से आपका भी नाम होगा। (जब मैं कहता हूं कि फंक्शन का मतलब है, लंबोदर फंक्शन नहीं)।
cglacet

3

इसे इस्तेमाल करे

d = {'a':'Apple', 'b':'Banana','c':'Carrot'}
a,b,c = [d[k] for k in ('a', 'b','c')]

परिणाम:

a == 'Apple'
b == 'Banana'
c == 'Carrot'

3

चेतावनी 1: डॉक्स में कहा गया है, यह सभी पायथन कार्यान्वयन पर काम करने की गारंटी नहीं है:

CPython कार्यान्वयन विवरण: यह फ़ंक्शन दुभाषिया में पायथन स्टैक फ्रेम समर्थन पर निर्भर करता है, जो कि पायथन के सभी कार्यान्वयन में मौजूद होने की गारंटी नहीं है। यदि पायथन स्टैक फ्रेम के बिना कार्यान्वयन में चल रहा है, तो यह फ़ंक्शन कोई भी नहीं लौटाता है।

चेतावनी 2: यह फ़ंक्शन कोड को छोटा बनाता है, लेकिन संभवतः यह पायथन दर्शन को उतना स्पष्ट करता है जितना आप कर सकते हैं। इसके अलावा, यह टिप्पणियों में जॉन क्रिस्टोफर जोन्स द्वारा इंगित मुद्दों को संबोधित नहीं करता है, हालांकि आप एक समान फ़ंक्शन बना सकते हैं जो कुंजियों के बजाय विशेषताओं के साथ काम करता है। यह केवल एक प्रदर्शन है जिसे आप कर सकते हैं यदि आप वास्तव में चाहते हैं!

def destructure(dict_):
    if not isinstance(dict_, dict):
        raise TypeError(f"{dict_} is not a dict")
    # the parent frame will contain the information about
    # the current line
    parent_frame = inspect.currentframe().f_back

    # so we extract that line (by default the code context
    # only contains the current line)
    (line,) = inspect.getframeinfo(parent_frame).code_context

    # "hello, key = destructure(my_dict)"
    # -> ("hello, key ", "=", " destructure(my_dict)")
    lvalues, _equals, _rvalue = line.strip().partition("=")

    # -> ["hello", "key"]
    keys = [s.strip() for s in lvalues.split(",") if s.strip()]

    if missing := [key for key in keys if key not in dict_]:
        raise KeyError(*missing)

    for key in keys:
        yield dict_[key]
In [5]: my_dict = {"hello": "world", "123": "456", "key": "value"}                                                                                                           

In [6]: hello, key = destructure(my_dict)                                                                                                                                    

In [7]: hello                                                                                                                                                                
Out[7]: 'world'

In [8]: key                                                                                                                                                                  
Out[8]: 'value'

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


1

ठीक है, अगर आप एक कक्षा में ये चाहते हैं तो आप हमेशा ऐसा कर सकते हैं:

class AttributeDict(dict):
    def __init__(self, *args, **kwargs):
        super(AttributeDict, self).__init__(*args, **kwargs)
        self.__dict__.update(self)

d = AttributeDict(a=1, b=2)

अच्छा लगा। धन्यवाद, लेकिन d ['a'] से कॉल सिंटैक्स को दा में बदलने का एक तरीका लगता है? और शायद उन तरीकों को जोड़ना जो इन मापदंडों तक अंतर्निहित रूप से पहुंच रखते हैं ...
हैमेट्रिक्स

0

@ शनफुमो जवाब के आधार पर मैं इस पर आया:

def destruct(dict): return (t[1] for t in sorted(dict.items()))

d = {'b': 'Banana', 'c': 'Carrot', 'a': 'Apple' }
a, b, c = destruct(d)

(आइटम के क्रम को ध्यान से देखें)


0

चूंकि पायथन में अपने प्रविष्टि क्रम को रखने के लिए शब्दकोशों की गारंटी है> = 3.7 , इसका मतलब है कि यह आजकल पूरी तरह से सुरक्षित और मुहावरेदार है:

params = {'a': 1, 'b': 2}
a, b = params.values()
print(a)
print(b)

आउटपुट:

1
2

2
महान! मेरे पद से केवल 9 साल लगे। :)
हैमेट्रिक्स

1
मुद्दा यह है कि आप ऐसा नहीं कर सकते b, a = params.values(), क्योंकि यह आदेश का उपयोग करता है नाम नहीं।
कोरमन

1
@ruohola यह इस समाधान के साथ मुद्दा है। यह नामों के लिए शब्दकोशों के क्रम पर निर्भर करता है, न कि खुद के नामों पर, यही वजह है कि मैंने इसे नकार दिया।
कोरमन

1
और अगर यह चाबी के आदेश पर निर्भर करता है तो यह एक बुरा समाधान है। itemgetterऐसा करने के लिए सबसे अधिक पायथोनिक तरीका है। यह पायथन 3.6 या उससे नीचे पर काम नहीं करेगा, और क्योंकि यह आदेश पर निर्भर करता है, यह पहली बार में भ्रमित हो सकता है।
कॉर्मन

-1

मुझे नहीं पता कि यह अच्छी शैली है, लेकिन

locals().update(params)

चाल चलेगा। आपके पास तब है a, bऔर जो कुछ भी आपके paramsआदेश में था , वही स्थानीय चर के रूप में उपलब्ध था ।


2
कृपया ध्यान दें कि यह एक बड़ी सुरक्षा समस्या हो सकती है यदि 'परम' शब्दकोश किसी भी तरह से उपयोगकर्ता-प्रदान किया गया हो और ठीक से फ़िल्टर न किया गया हो।
जसक कोनजेनी

9
Docs.python.org/library/functions.html#locals : को उद्धृत करने के लिए : नोट: इस शब्दकोश की सामग्री को संशोधित नहीं किया जाना चाहिए; परिवर्तन दुभाषिया द्वारा उपयोग किए जाने वाले स्थानीय और मुक्त चर के मूल्यों को प्रभावित नहीं कर सकता है।
जोहान रिट्जेल

4
सबक सीखा। Thx, दोस्तों।
जोहान्स चररा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.