2014-11-05 5 views
21

में ऑर्डर्ड डिक्ट का उपयोग करना क्या एक ऑर्डरर्ड डिक्ट इंस्टेंस को उस फ़ंक्शन पर पास करना संभव है जो **kwargs वाक्यविन्यास का उपयोग करता है और ऑर्डरिंग को बनाए रखता है?** kwargs

मैं क्या करना चाहते हैं क्या है:

def I_crave_order(**kwargs): 
    for k, v in kwargs.items(): 
     print k, v 

example = OrderedDict([('first', 1), ('second', 2), ('third', -1)]) 

I_crave_order(**example) 
>> first 1 
>> second 2 
>> third -1 

हालांकि वास्तविक परिणाम है:

>> second 2 
>> third -1 
>> first 1 

यानी, ठेठ यादृच्छिक dict आदेश।

मैं अन्य उपयोगों जहां स्पष्ट रूप से आदेश की स्थापना अच्छा है, तो मैं **kwargs बनाए रखना और केवल एक नियमित रूप से तर्क

+0

विस्तृत उत्तरदाताओं के लिए धन्यवाद। मैंने जो किया वह एक वैकल्पिक पहला तर्क (एक आदेश दिया गया आदेश) की अनुमति देने के लिए किया गया था जो प्रदान किए जाने पर ** kwargs को प्राथमिकता में उपयोग किया जाएगा। महान जानकारी, हालांकि – theodox

+0

** यह भी देखें: ** https://duckduckgo.com/?q=pep468 – dreftymac

उत्तर

22

अजगर 3.6, the keyword argument order is preserved के रूप में के रूप में OrderedDict पारित नहीं चाहते हैं। 3.6 से पहले, यह संभव नहीं है क्योंकि OrderedDictdict में बदल जाता है।


पहली बात को एहसास है कि मूल्य आप **example में पास स्वचालित रूप से **kwargs में मूल्य नहीं होता है।

def f(a, **kwargs): 
    pass 
example = {'a': 1, 'b': 2} 
f(**example) 

या इस मामले में, यह उदाहरण में उन लोगों की तुलना में अधिक मान होगा जहां: बिल्कुल

example = {'b': 2} 
f(a=1, c=3, **example) 

या यहां तक ​​कि कोई ओवरलैप:

इस मामले पर विचार करें, जहां kwargs केवल example का हिस्सा होगा
example = {'a': 1} 
f(b=2, **example) 

तो, आप जो चाह रहे हैं वास्तव में कोई मतलब नहीं है।

फिर भी, यह अच्छा होगा यदि वहाँ कोई रास्ता है कि आप एक आदेश दिया **kwargs जाएँ, चाहे निर्दिष्ट करने के लिए थे हो सकता है जहां कीवर्ड से वे दिखाई देते हैं में से स्पष्ट कीवर्ड आर्ग आया था, के आइटम के सभी के द्वारा पीछा किया **example क्रम में वे example में दिखाई देते हैं (यदि exampledict थे, तो यह मनमाना हो सकता है, लेकिन यदि यह OrderedDict था तो भी सार्थक हो सकता है)।

सभी समझदार विवरणों को परिभाषित करना, और निष्पादन को स्वीकार्य रखना, यह लगता है कि यह कठिन लगता है। विचार पर कुछ चर्चा के लिए PEP 468, और जुड़े धागे देखें। ऐसा लगता है कि इस बार चारों ओर रुका हुआ है, लेकिन अगर कोई इसे उठाता है और इसे चैंपियन करता है (और लोगों के साथ खेलने के लिए एक संदर्भ कार्यान्वयन लिखता है - जो सीपीआई से OrderedDict तक पहुंच योग्य है, लेकिन उम्मीद है कि 3.5+), मुझे संदेह है कि यह अंततः भाषा में आ जाएगा।


वैसे, ध्यान दें कि यदि इस संभव थे, यह लगभग निश्चित रूप से निर्माता में OrderedDict खुद के लिए इस्तेमाल किया जाएगा। लेकिन अगर आपको लगता है कि कोशिश, तुम सब कर रहे हैं स्थायी आदेश के रूप में कुछ मनमाने ढंग से आदेश ठंड है:

>>> d = OrderedDict(a=1, b=2, c=3) 
OrderedDict([('a', 1), ('c', 3), ('b', 2)]) 

इस बीच, क्या विकल्प है?

ठीक है, स्पष्ट विकल्प सिर्फ बजाय इसे खोल का एक सामान्य तर्क के रूप में example पारित करने के लिए है:

def f(example): 
    pass 
example = OrderedDict([('a', 1), ('b', 2)]) 
f(example) 

या, निश्चित रूप से, आप *args का उपयोग करें और tuples के रूप में आइटम पारित कर सकते हैं, लेकिन है कि आम तौर भद्दा है ।

पीईपी से जुड़े धागे में कुछ और कामकाज हो सकते हैं, लेकिन वास्तव में, उनमें से कोई भी इससे बेहतर नहीं होगा। (इसके अलावा ... आईआईआरसी, ली हाओई अपने MacroPy के आधार पर एक समाधान के साथ आया, ताकि क्रमशः कीवर्ड तर्कों को पारित किया जा सके, लेकिन मुझे विवरण याद नहीं हैं। सामान्य रूप से मैक्रोपी समाधान अद्भुत हैं यदि आप मैक्रोपी का उपयोग करने और कोड लिखने के इच्छुक हैं जो पाइथन की तरह नहीं पढ़ता है, लेकिन यह हमेशा उपयुक्त नहीं है ...)

+0

क्या आप इस उत्तर को पायथन 3.6 के लिए अपडेट कर सकते हैं? – Moberg

2

जब पाइथन **kwargs हस्ताक्षर में निर्माण करता है, तो यह kwargs "मैपिंग" होने की अपेक्षा करता है, जिसका अर्थ है दो चीजें: (1) मैपिंग द्वारा निहित कुंजियों की एक पुनरावृत्ति प्राप्त करने के लिए kwargs.keys() पर कॉल करने में सक्षम होने के लिए, और (2) kwargs.__getitem__(key) को keys() द्वारा लौटाए गए प्रत्येक कुंजी के लिए बुलाया जा सकता है और परिणामी मान उस के लिए वांछित होना चाहिए कुंजी।

आंतरिक रूप से, अजगर फिर "परिणत" करेगा जो मानचित्रण है एक शब्दकोश में, एक तरह से इस तरह:

**kwargs -> {key:kwargs[key] for key in kwargs.keys()} 

यह एक छोटे से मूर्खतापूर्ण लग रहा है अगर आपको लगता है कि kwargs पहले से ही एक dict है - और यह हो सकता है, के बाद से वहाँ एक है कि में पारित हो जाता है से एक पूरी तरह से बराबर dict के निर्माण के लिए कोई कारण नहीं है।

लेकिन जब kwargs जरूरी dict नहीं है, तो यह बहुत एक उपयुक्त डिफ़ॉल्ट डेटा संरचना में नीचे उसकी सामग्री को लाने के लिए मायने रखती है वह कोड जो अनपॅकिंग तर्क करता है हमेशा जानता है कि यह किसके साथ काम कर रहा है।

तो, आप कर सकते हैं जिस तरह से एक निश्चित डेटा प्रकार है, लेकिन एक सुसंगत आर्ग-unpacking प्रोटोकॉल की खातिर dict करने के लिए रूपांतरण की वजह से विसंकुलित हो जाता है साथ गड़बड़ है, यह सिर्फ होता है कि के आदेश पर की गारंटी देता है रखने तर्क अनपॅकिंग संभव नहीं है (क्योंकि dict उस ऑर्डर का ट्रैक नहीं रखता है जिसमें तत्व जोड़े जाते हैं)। यदि पाइथन की भाषा **kwargs को dict के बजाय OrderedDict में लाया गया है (जिसका अर्थ है कि कीवर्ड तर्क के रूप में कुंजी का ऑर्डर वह क्रम होगा जिसमें वे ट्रैवर्स हैं), तो OrderedDict या कुछ अन्य डेटा संरचना को पास करके keys() सम्मान कुछ प्रकार के ऑर्डरिंग, आप तर्कों पर एक निश्चित आदेश की उम्मीद कर सकते हैं। यह कार्यान्वयन का सिर्फ एक quirk है कि dict मानक के रूप में चुना जाता है, और कुछ अन्य प्रकार के मानचित्रण नहीं।

class MyOrderedDict(object): 
    def __init__(self, odict): 
     self._odict = odict 

    def __repr__(self): 
     return self._odict.__repr__() 

    def __getitem__(self, item): 
     return 42 

    def __setitem__(self, item, value): 
     self._odict[item] = value 

    def keys(self): 
     return self._odict.keys() 

तब मुद्रित करने के लिए एक समारोह को परिभाषित:

यहां कक्षा जो हमेशा 42 के रूप में सभी पैक मूल्यों व्यवहार करता है (भले ही वे वास्तव में नहीं हैं) है कि "अनपैक किया जा" सकता है, लेकिन की एक गूंगा उदाहरण है पैक सामग्री:

def foo(**kwargs): 
    for k, v in kwargs.iteritems(): 
     print k, v 

और एक मूल्य बनाने के लिए और इसे आज़माने:

In [257]: import collections; od = collections.OrderedDict() 

In [258]: od['a'] = 1; od['b'] = 2; od['c'] = 3; 

In [259]: md = MyOrderedDict(od) 

In [260]: print md 
OrderedDict([('a', 1), ('b', 2), ('c', 3)]) 

In [261]: md.keys() 
Out[261]: ['a', 'b', 'c'] 

In [262]: foo(**md) 
a 42 
c 42 
b 42 

यह ग कुंजी-मूल्य जोड़े की आभासी डिलीवरी (यहां, बेवकूफ हमेशा 42 लौट रही है) **kwargs पाइथन में कैसे काम करता है इसके साथ टिंकर करने की आपकी क्षमता की सीमा है।

*args को अनपॅक किए जाने के साथ टंकण करने के लिए थोड़ा अधिक लचीलापन है। उस पर अधिक जानकारी के लिए यह प्रश्न देखें: < Does argument unpacking use iteration or item-getting?>।

13

This is now the default in python 3.6

Python 3.6.0a4+ (default:d43f819caea7, Sep 8 2016, 13:05:34) 
>>> def func(**kw): print(kw.keys()) 
... 
>>> func(a=1, b=2, c=3, d=4, e=5) 
dict_keys(['a', 'b', 'c', 'd', 'e']) # expected order 

अन्य उत्तरों के अनुसार इसे पहले करना संभव नहीं है।

संबंधित मुद्दे