शब्दकोश की तरह सुरक्षित "प्राप्त" विधि की सूची क्यों नहीं है?


264

सूची में डिक्शनरी जैसी सुरक्षित "प्राप्त" विधि क्यों नहीं है?

>>> d = {'a':'b'}
>>> d['a']
'b'
>>> d['c']
KeyError: 'c'
>>> d.get('c', 'fail')
'fail'

>>> l = [1]
>>> l[10]
IndexError: list index out of range

1
सूचियों का उपयोग शब्दकोशों की तुलना में विभिन्न उद्देश्यों के लिए किया जाता है। सूची के विशिष्ट उपयोग मामलों के लिए गेट () की आवश्यकता नहीं है। हालाँकि, शब्दकोश के लिए () काफी उपयोगी है।
mgronber

42
तुम हमेशा IndexError को ऊपर उठाने के बिना एक सूची से बाहर एक खाली sublist प्राप्त कर सकते हैं आप के बजाय एक टुकड़ा के लिए पूछना: l[10:11]के बजाय l[10]उदाहरण के लिए,। () Th
सबलिस्ट

56
यहां कुछ के विपरीत, मैं एक सुरक्षित विचार का समर्थन करता हूं .get। यह इसके बराबर होगा l[i] if i < len(l) else default, लेकिन अधिक पठनीय, अधिक संक्षिप्त, और iइसे फिर से पुनर्गणना किए बिना एक अभिव्यक्ति होने की अनुमति देगा
पॉल ड्रेपर

6
आज मैं कामना करता हूं कि यह अस्तित्व में रहे। मैं एक महंगे फ़ंक्शन का उपयोग करता हूं जो एक सूची देता है, लेकिन मैं केवल पहला आइटम चाहता था, या Noneयदि कोई मौजूद नहीं था। यह कहना अच्छा x = expensive().get(0, None)होगा, इसलिए मुझे एक अस्थायी चर में महंगी की बेकार वापसी नहीं करनी होगी।
रयान हाईबर्ट

2
@ मेरा जवाब आपको stackoverflow.com/a/23003811/246265
Jake

जवाबों:


112

अंततः यह एक सुरक्षित .getतरीका नहीं है क्योंकि एक dictसाहचर्य संग्रह (नाम के साथ मूल्य जुड़े हुए हैं) जहां यह जांचना अक्षम है कि क्या कोई कुंजी मौजूद है (और उसका मान लौटाएं) बिना किसी अपवाद को फेंक दिए, जबकि यह सुपर तुच्छ है सूची तत्वों तक पहुंचने वाले अपवादों से बचने के लिए (क्योंकि lenविधि बहुत तेज़ है)। .getविधि आप एक नाम के साथ जुड़े मूल्य क्वेरी करने के लिए, सीधे शब्दकोश (जो और अधिक की तरह होगा कि तुम क्या अपनी सूची के लिए कह रहे हैं) में 37 वें आइटम तक नहीं पहुंच की अनुमति देता है।

बेशक, आप इसे आसानी से लागू कर सकते हैं:

def safe_list_get (l, idx, default):
  try:
    return l[idx]
  except IndexError:
    return default

आप इसे __builtins__.listकंस्ट्रक्टर पर भी रोक सकते हैं __main__, लेकिन यह एक कम परिवर्तन होगा क्योंकि अधिकांश कोड इसका उपयोग नहीं करते हैं। यदि आप बस अपने स्वयं के कोड द्वारा बनाई गई सूचियों के साथ इसका उपयोग करना चाहते हैं, तो आप बस उपवर्ग listऔर getविधि जोड़ सकते हैं ।


24
पायथन बंदर के प्रकारों को बनाने की अनुमति नहीं देता है जैसेlist
इमरान

7
@ सीसीजेड: .getऐसी समस्या को हल करता है जिसमें सूची नहीं होती है - डेटा प्राप्त नहीं होने पर अपवादों से बचने का एक कुशल तरीका। यह सुपर तुच्छ है और यह जानने के लिए बहुत ही कुशल है कि एक वैध सूची सूचकांक क्या है, लेकिन एक शब्दकोश में प्रमुख मूल्यों के लिए ऐसा करने का कोई विशेष तरीका नहीं है।
निक बैस्टिन

10
मुझे नहीं लगता कि यह दक्षता के बारे में बिल्कुल भी है - अगर एक कुंजी एक शब्दकोश में मौजूद है और / या किसी आइटम को लौटाने की जाँच कर रही है O(1)। यह जाँच के रूप में कच्चे शब्दों में बहुत तेज़ नहीं होगा len, लेकिन एक जटिलता के दृष्टिकोण से वे सभी हैं O(1)। सही उत्तर विशिष्ट उपयोग / शब्दार्थ एक है ...
मार्क लॉन्गेयर

3
@ मर्क: सभी ओ (1) समान नहीं बनाए गए हैं। इसके अलावा, dictकेवल सबसे अच्छा मामला ओ (1) है, सभी मामलों में नहीं।
निक बैस्टिन

4
मुझे लगता है कि लोग यहां की बात याद कर रहे हैं। चर्चा दक्षता के बारे में नहीं होनी चाहिए। कृपया समयपूर्व अनुकूलन के साथ रुकें। यदि आपका कार्यक्रम बहुत धीमा है, तो आप या तो गाली दे रहे हैं .get()या आपको अपने कोड (या वातावरण) में कहीं और समस्या है। ऐसी विधि का उपयोग करने का बिंदु कोड पठनीयता है। "वेनिला" तकनीक को हर स्थान पर कोड की चार पंक्तियों की आवश्यकता होती है जो इसे करने की आवश्यकता होती है। .get()तकनीक केवल एक की आवश्यकता है और आसानी से बाद में विधि कॉल (जैसे के साथ श्रृंखलित किया जा सकता है my_list.get(2, '').uppercase())।
टायलर क्रॉम्पटन

67

यह काम करता है यदि आप पहला तत्व चाहते हैं, जैसे my_list.get(0)

>>> my_list = [1,2,3]
>>> next(iter(my_list), 'fail')
1
>>> my_list = []
>>> next(iter(my_list), 'fail')
'fail'

मुझे पता है कि यह वास्तव में नहीं है जो आपने मांगा था लेकिन यह दूसरों की मदद कर सकता है।


7
कार्यात्मक प्रोग्रामिंग-एस्के की तुलना में कम पायथोनिक
एरिक

next(iter(my_list[index:index+1]), 'fail')किसी भी सूचकांक के लिए अनुमति देता है, न केवल 0. या उससे कम एफपी लेकिन यकीनन अधिक पायथन, और लगभग निश्चित रूप से अधिक पठनीय my_list[index] if index < len(my_list) else 'fail':।
अल्फाबेटसअप

47

शायद इसलिए क्योंकि यह सिर्फ सूची शब्दार्थ के लिए बहुत मायने नहीं रखता था। हालाँकि, आप आसानी से उपवर्ग बनाकर अपना खुद का बना सकते हैं।

class safelist(list):
    def get(self, index, default=None):
        try:
            return self.__getitem__(index)
        except IndexError:
            return default

def _test():
    l = safelist(range(10))
    print l.get(20, "oops")

if __name__ == "__main__":
    _test()

5
यह अब तक, ओपी का जवाब देने वाला सबसे अजगर है। ध्यान दें कि आप एक सबलिस्ट भी निकाल सकते हैं, जो पायथन में एक सुरक्षित ऑपरेशन है। Mylist = [1, 2, 3] को देखते हुए, आप अपवाद को ट्रिगर किए बिना, mylist [8: 9] के साथ 9 वें तत्व को निकालने का प्रयास कर सकते हैं। आप तब परीक्षण कर सकते हैं यदि सूची खाली है और, यदि यह रिक्त नहीं है, तो दिए गए सूची से एकल तत्व निकालें।
jose.angel.jimenez

1
यह स्वीकृत उत्तर होना चाहिए, न कि अन्य गैर-पाइथोनिक वन-लाइनर हैक्स, खासकर क्योंकि यह शब्दकोशों के साथ समरूपता का संरक्षण करता है।
एरिक

1
आपकी अपनी सूचियों को उपवर्ग में रखने के बारे में कुछ भी नहीं है, क्योंकि आपको एक अच्छी getविधि की आवश्यकता है । पठनीयता मायने रखती है। और पठनीयता हर अतिरिक्त अनावश्यक वर्ग से ग्रस्त है। try / exceptउपवर्ग बनाने के बिना दृष्टिकोण का उपयोग करें ।
जेजेकोमोन

@Jeyekomon यह सब पाइक्लोनिक उप-आवरण द्वारा बॉयलरप्लेट को कम करने के लिए है।
कीथ

42

उपयोग .get के बजाय, इस तरह का उपयोग सूचियों के लिए ठीक होना चाहिए। बस एक उपयोग अंतर है।

>>> l = [1]
>>> l[10] if 10 < len(l) else 'fail'
'fail'

15
यह विफल हो जाता है अगर हम नवीनतम तत्व -1 प्राप्त करने का प्रयास करते हैं।
प्रेटोबोम्बा

ध्यान दें कि यह परिपत्र रूप से लिंक की गई सूची ऑब्जेक्ट्स के लिए काम नहीं करता है। इसके अतिरिक्त, सिंटैक्स का कारण बनता है जो मुझे "स्कैनिंग ब्लॉक" कॉल करना पसंद है। कोड के माध्यम से स्कैन करते समय यह देखने के लिए कि यह क्या करता है, यह एक ऐसी रेखा है जो मुझे एक पल के लिए धीमा कर देती है।
टायलर क्रॉम्पटन

इनलाइन अगर / अन्यथा 2.6 की तरह पुराने अजगर के साथ काम नहीं करता है (या यह 2.5 है?)
एरिक

3
@ टायलर क्रॉम्पटन: अजगर में कोई गोलाकार रूप से जुड़ी सूची नहीं है। यदि आपने अपने दम पर एक लिखा है तो आप एक .getविधि को लागू करने के लिए स्वतंत्र हैं (इसके अलावा मुझे यकीन नहीं है कि आप कैसे समझाएंगे कि इस मामले में सूचकांक का क्या मतलब है, या यह कभी क्यों विफल हो जाएगा)।
निक बैस्टिन

एक विकल्प जो नकारात्मक संकेतों को समाप्त करता हैlst[i] if -len(lst) <= i < len(l) else 'fail'
माइक

17

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

>>> i = 3
>>> a = [1, 2, 3, 4]
>>> next(iter(a[i:]), 'fail')
4
>>> next(iter(a[i + 1:]), 'fail')
'fail'

1
मुझे यह पसंद है, हालांकि इसके लिए पहले एक नई उप-सूची बनाने की आवश्यकता है।
रिक

15

क्रेडिट्स को jose.angel.jimenez


"Oneliner" प्रशंसकों के लिए ...


यदि आप सूची का पहला तत्व चाहते हैं या यदि सूची खाली है तो आप डिफ़ॉल्ट मान चाहते हैं:

liste = ['a', 'b', 'c']
value = (liste[0:1] or ('default',))[0]
print(value)

रिटर्न a

तथा

liste = []
value = (liste[0:1] or ('default',))[0]
print(value)

रिटर्न default


अन्य तत्वों के उदाहरण ...

liste = ['a', 'b', 'c']
print(liste[0:1])  # returns ['a']
print(liste[1:2])  # returns ['b']
print(liste[2:3])  # returns ['c']

डिफ़ॉल्ट कमबैक के साथ…

liste = ['a', 'b', 'c']
print((liste[0:1] or ('default',))[0])  # returns a
print((liste[1:2] or ('default',))[0])  # returns b
print((liste[2:3] or ('default',))[0])  # returns c

के साथ परीक्षण किया गया Python 3.6.0 (v3.6.0:41df79263a11, Dec 22 2016, 17:23:13)


1
लघु विकल्प value, = liste[:1] or ('default',):। ऐसा लगता है कि आपको कोष्ठक की आवश्यकता है।
qräbnö

13

सबसे अच्छी चीज जो आप कर सकते हैं वह है सूची को एक तानाशाही में बदलना और फिर इसे प्राप्त करने की विधि के साथ एक्सेस करना:

>>> my_list = ['a', 'b', 'c', 'd', 'e']
>>> my_dict = dict(enumerate(my_list))
>>> print my_dict
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}
>>> my_dict.get(2)
'c'
>>> my_dict.get(10, 'N/A')

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

3
हालांकि बहुत अक्षम है। नोट: उस zip range lenचीज़ के बजाय , कोई भी इस्तेमाल कर सकता हैdict(enumerate(my_list))
Marian

3
यह सबसे अच्छी बात नहीं है, यह सबसे खराब चीज है जो आप कर सकते हैं।
एरिकाबवर्क

3
यदि आप प्रदर्शन पर विचार करते हैं तो यह सबसे खराब बात है ... यदि आप प्रदर्शन के बारे में परवाह करते हैं तो आप अजगर जैसी व्याख्या की गई भाषा में कोड नहीं करते हैं। मैं एक सुंदर, शक्तिशाली और pythonic शब्दकोश का उपयोग करके इस समाधान को ढूंढता हूं। आरंभिक अनुकूलन वैसे भी बुरे होते हैं इसलिए चलो एक तानाशाही है और बाद में देखें कि यह एक अड़चन है।
एरिक

7

इसलिए मैंने इसमें कुछ और शोध किया और यह पता चला कि इसके लिए कुछ खास नहीं है। जब मुझे list.index (मान) मिला तो मैं उत्साहित हो गया, यह एक निर्दिष्ट आइटम का सूचकांक लौटाता है, लेकिन एक विशिष्ट सूचकांक पर मूल्य प्राप्त करने के लिए कुछ भी नहीं है। इसलिए यदि आप safe_list_get समाधान का उपयोग नहीं करना चाहते हैं जो मुझे लगता है कि बहुत अच्छा है। यहां कुछ 1 लाइनर दिए गए हैं, यदि कथन जो परिदृश्य के आधार पर आपके लिए काम कर सकते हैं:

>>> x = [1, 2, 3]
>>> el = x[4] if len(x) > 4 else 'No'
>>> el
'No'

आप 'नहीं' के बजाय कोई भी उपयोग नहीं कर सकते हैं, जो अधिक समझ में आता है।

>>> x = [1, 2, 3]
>>> i = 2
>>> el_i = x[i] if len(x) == i+1 else None

इसके अलावा अगर आप सूची में पहला या अंतिम आइटम प्राप्त करना चाहते हैं, तो यह काम करता है

end_el = x[-1] if x else None

आप इन्हें फंक्शन्स में भी बना सकते हैं लेकिन मुझे अभी भी IndexError अपवाद समाधान पसंद है। मैंने safe_list_getसमाधान के डम्मीड डाउन संस्करण के साथ प्रयोग किया और इसे थोड़ा सरल (कोई डिफ़ॉल्ट नहीं) बनाया:

def list_get(l, i):
    try:
        return l[i]
    except IndexError:
        return None

सबसे तेज़ क्या है यह देखने के लिए बेंचमार्क नहीं किया गया।


1
वास्तव में अजगर नहीं है।
एरिक

@ कौन सा स्निपेट? मुझे लगता है कि प्रयास को छोड़कर, इसे फिर से देखकर सबसे अधिक समझ में आता है।
राडेक

एक स्टैंडअलोन फ़ंक्शन पाइथोनिक नहीं है। अपवाद वास्तव में थोड़ा अधिक पायथोनिक हैं, लेकिन बहुत ज्यादा नहीं है क्योंकि यह प्रोग्रामिंग भाषाओं में ऐसा सामान्य पैटर्न है। बहुत अधिक पाइथोनिक एक नई वस्तु है जो बिलिन प्रकार listको उप-वर्ग द्वारा बढ़ाता है। इस तरह से कंस्ट्रक्टर एक listया कुछ भी ले सकता है जो एक सूची की तरह व्यवहार करता है, और नया उदाहरण एक की तरह व्यवहार करता है list। नीचे कीथ का उत्तर देखें जिसे स्वीकार किया जाना चाहिए।
एरिक

1
@ एरिक ने प्रश्न को ओओपी-विशिष्ट के रूप में नहीं बताया है, लेकिन "सूचियों dict.get()को पकड़ने के बजाय सूची सूचकांक संदर्भ से डिफ़ॉल्ट मान वापस करने के लिए कोई समानता क्यों नहीं है IndexError? तो यह वास्तव में भाषा / पुस्तकालय सुविधा (और ओओपी नहीं है) के बारे में है? बनाम एफपी संदर्भ)। इसके अलावा, शायद किसी को 'पीथोनिक' के आपके उपयोग को क्वालिफाई करना होगा क्योंकि शायद डब्ल्यूडब्ल्यूजीडी (एफपी पायथन के लिए उसका तिरस्कार अच्छी तरह से जाना जाता है) और जरूरी नहीं कि वह केवल PEP8 / 20 को संतुष्ट करे।
21

1
el = x[4] if len(x) == 4 else 'No'- क्या आपका मतलब है len(x) > 4? x[4]बाहर की सीमा है अगर len(x) == 4
mic

4

शब्दकोश लुक अप के लिए हैं। यह पूछने के लिए समझ में आता है कि क्या कोई प्रविष्टि मौजूद है या नहीं। सूची आमतौर पर पुनरावृत्त होती हैं। यह पूछना आम नहीं है कि क्या L [10] मौजूद है, बल्कि यदि L की लंबाई 11 है।


हां, आप सहमत हैं। लेकिन मैंने पृष्ठ "/ समूह / Page_name" के सापेक्ष url को पार्स कर दिया। इसे '/' से विभाजित करें और जाँचें कि क्या PageName निश्चित पृष्ठ के बराबर है। लंबाई के लिए अतिरिक्त जाँच करने या अपवाद को पकड़ने या अपना कार्य लिखने के बजाय [url.split ('/')। Get_from_index (2, कोई नहीं) == "लालाला"] जैसे कुछ लिखना आरामदायक होगा। संभवतः आप सही हैं यह केवल असामान्य माना जाता है। वैसे भी मैं अभी भी इससे सहमत नहीं हूं) =)
CSZ

@ निक बास्टिन: कुछ भी गलत नहीं है। यह सरलता और कोडिंग की गति के बारे में है।
CSZ

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

-1

आपका usecase मूल रूप से केवल तब के लिए प्रासंगिक है जब एक निश्चित लंबाई के सरणियों और मैट्रिक्स कर रहे हों, ताकि आप जान सकें कि वे कितने समय से पहले हाथ में हैं। उस स्थिति में आप आम तौर पर उन्हें हाथ से भरने से पहले भी बनाते हैं, कोई नहीं या 0 के साथ, ताकि वास्तव में आप पहले से मौजूद किसी भी इंडेक्स का उपयोग करेंगे।

आप यह कह सकते हैं: मुझे बहुत बार शब्दकोशों पर .get () की आवश्यकता है। एक पूर्णकालिक प्रोग्रामर के रूप में दस साल के बाद मुझे नहीं लगता कि मुझे कभी किसी सूची में इसकी आवश्यकता है। :)


टिप्पणियों में मेरे उदाहरण के बारे में कैसे? क्या अधिक सरल और पठनीय है? (url.split ('/')। getFromIndex (2) == "लालला") या (परिणाम = url.split (); len (परिणाम)> 2 और परिणाम [2] = "lalala")। और हां, मुझे पता है कि मैं खुद ऐसे फंक्शन लिख सकता हूं =) लेकिन मुझे आश्चर्य था कि ऐसा फंक्शन बिलकुल नहीं है।
CSZ

1
Id 'अपने मामले में कहें कि आप इसे गलत कर रहे हैं। URL हैंडलिंग या तो मार्गों (पैटर्न मिलान) या ऑब्जेक्ट ट्रैवर्सल द्वारा किया जाना चाहिए। लेकिन, अपने विशिष्ट मामले का जवाब देने के लिए 'lalala' in url.split('/')[2:]:। लेकिन यहां आपके समाधान के साथ समस्या यह है कि आप केवल दूसरे तत्व को देखते हैं। यदि URL '/ बंदरबाँट / लालाला' हो तो क्या होगा? TrueURL अमान्य होने के बावजूद आपको मिल जाएगा ।
लेन्नर्ट रेग्रोब

मैंने केवल दूसरा तत्व लिया क्योंकि मुझे केवल दूसरे तत्व की आवश्यकता थी। लेकिन हां, स्लाइस अच्छा काम करने का विकल्प लगता है
CSZ

@CSZ: लेकिन फिर पहले तत्व को अनदेखा किया जाता है, और उस स्थिति में आप इसे छोड़ सकते हैं। :) देखें कि मेरा क्या मतलब है, उदाहरण वास्तविक जीवन में अच्छी तरह से काम नहीं करता है।
लेन्नर्ट रेग्रोब
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.