क्या मुझे पायथन डाइक पर 'has_key ()' या 'in' का उपयोग करना चाहिए?


910

मुझे आश्चर्य है कि क्या करना बेहतर है:

d = {'a': 1, 'b': 2}
'a' in d
True

या:

d = {'a': 1, 'b': 2}
d.has_key('a')
True

जवाबों:


1286

in निश्चित रूप से अधिक पायथोनिक है।

वास्तव has_key()में अजगर 3.x में हटा दिया गया था


3
एक अतिरिक्त के रूप में, अजगर 3 में, कुंजी के बजाय मूल्यों में होने की जाँच करने के लिए,, d.values में >>> 1 () की कोशिश
रिज़ा

217
एक अर्ध-गोत्र हालांकि बचने के लिए है कि आप यह सुनिश्चित करें: "some_dict में कुंजी" बजाय "key_dict.keys ()" में। दोनों शब्दार्थ के समतुल्य हैं, लेकिन प्रदर्शन-वार बाद वाला बहुत धीमा (O (n) बनाम O (1)) है। मैंने देखा है कि लोगों को "डिक्टेट.कीक्स ()" में यह अधिक स्पष्ट और इसलिए बेहतर लगता है।
एडम पार्किन

2
@AdamParkin मैंने अपने जवाब में अपनी टिप्पणी का प्रदर्शन किया stackoverflow.com/a/41390975/117471
ब्रूनो ब्रोंस्की

8
@AdamParkin पायथन 3 में, keys()एक प्रतिलिपि के बजाय एक शब्दकोश में एक सेट जैसा दृश्य है, इसलिए x in d.keys()O (1) है। फिर भी, x in dअधिक पायथोनिक है।
आर्थर टाका

2
@AdamParkin दिलचस्प है, मैंने ऐसा नहीं देखा। मुझे लगता है कि क्योंकि x in d.keys()यह निर्माण करना चाहिए और एक अस्थायी वस्तु को नष्ट करना चाहिए, जो कि आवंटित स्मृति आवंटन के साथ पूरा होता है, जहां x in d.keys()सिर्फ एक अंकगणितीय ऑपरेशन (हैश की गणना) और एक लुकअप कर रहा है। ध्यान दें कि d.keys()यह केवल लगभग 10 गुना लंबा है, जो अभी भी वास्तव में लंबा नहीं है। मैंने जाँच नहीं की है लेकिन मुझे अभी भी पूरा यकीन है कि यह केवल O (1) है।
आर्थर टाका

253

in न केवल लालित्य में (और नहीं पदावनत;; बल्कि प्रदर्शन में भी, जैसे:

$ python -mtimeit -s'd=dict.fromkeys(range(99))' '12 in d'
10000000 loops, best of 3: 0.0983 usec per loop
$ python -mtimeit -s'd=dict.fromkeys(range(99))' 'd.has_key(12)'
1000000 loops, best of 3: 0.21 usec per loop

हालांकि निम्नलिखित अवलोकन हमेशा सच नहीं होता है, आप देखेंगे कि आमतौर पर , पायथन में, तेज समाधान अधिक सुरुचिपूर्ण और पायथन है; यही कारण -mtimeitहै कि एसओ मददगार है - यह सिर्फ यहाँ और वहाँ सौ नैनोसेकंड बचाने के बारे में नहीं है ! -)


4
इसके लिए धन्यवाद, ने पुष्टि की कि "some_dict में" वास्तव में O (1) बहुत आसान है (1999 कहने के लिए 99 को बढ़ाने की कोशिश करें, और आप पाएंगे कि रनटाइम लगभग उसी के बारे में है)।
एडम पार्किन

2
has_keyO (1) भी प्रतीत होता है।
डैन-gph


42

dict.has_key()अगर (और केवल अगर) का उपयोग करें तो आपके कोड को 2.3 से पहले पायथन संस्करणों द्वारा चलाया जा सकता है (जब key in dictपेश किया गया था)।


1
2013 में WebSphere अपडेट Jython 2.1 को अपनी मुख्य स्क्रिप्टिंग भाषा के रूप में उपयोग करता है। तो यह दुर्भाग्य से अभी भी नोट करने के लिए एक उपयोगी बात है, पाँच साल बाद आपने इसे नोट किया।
आर्टऑफवर्फ

23

एक उदाहरण है जहां in वास्तव में आपके प्रदर्शन को मारता है।

यदि आप inएक O (1) कंटेनर का उपयोग करते हैं, जो केवल लागू करता है __getitem__और has_key()नहीं __contains__तो आप O (N) खोज में O (1) खोज को चालू कर देंगे (जैसा inकि रैखिक खोज में वापस आता है )__getitem__ )।

फिक्स स्पष्ट रूप से तुच्छ है:

def __contains__(self, x):
    return self.has_key(x)

6
जब यह पोस्ट किया गया था तब यह जवाब लागू था, लेकिन 99.95% पाठक इसे सुरक्षित रूप से अनदेखा कर सकते हैं। में सबसे मामलों, अगर आप कुछ के साथ काम कर रहे हैं इस अस्पष्ट आप इसे पता चल जाएगा।
wizzwizz4

2
यह वास्तव में कोई मुद्दा नहीं है। has_key()है अजगर 2 शब्दकोशों के लिए विशिष्टin/ __contains__उपयोग करने के लिए सही एपीआई है; उन कंटेनरों के लिए जहां एक पूर्ण स्कैन अपरिहार्य है , वैसे भी कोई has_key()विधि नहीं है , और यदि कोई ओ (1) दृष्टिकोण है, तो वह उपयोग-केस विशिष्ट होगा और इसलिए समस्या के लिए सही डेटा प्रकार चुनने के लिए डेवलपर तक।
मार्टिन पीटर्स

15

has_keyएक शब्दकोश विधि है, लेकिन inकिसी भी संग्रह पर काम करेगा, और यहां तक __contains__कि लापता होने पर, inपता लगाने के लिए संग्रह को पुनरावृत्त करने के लिए किसी अन्य विधि का उपयोग करेगा।


1
और iterators पर भी काम करता है "x in xrange (90, 200) <=> 90 <= x <200"
u0b34a0f6ae

1
…: यह एक बहुत बुरा विचार लगता है: २० के बजाय ५० ऑपरेशन
क्लेमेंट

1
@ क्लेमेंट पायथन 3 में, वस्तुओं inपर परीक्षण करना वास्तव में काफी कुशल है range। मैं अजगर 2 पर इसकी दक्षता के बारे में इतना निश्चित नहीं हूं xrange, हालांकि। ;)
पीएम 2Ring

@ पायथन 3 में क्लेमेंट नहीं; यदि मूल्य सीमा में है या नहीं, तो __contains__तुच्छ गणना कर सकते हैं।
मार्टिन पीटर्स

1
@AlexandreHuat आपकी टाइमिंग में rangeहर बार एक नया उदाहरण बनाने का ओवरहेड शामिल है। एकल, पहले से मौजूद उदाहरण का उपयोग करके "समयावधि में पूर्णांक" परीक्षण मेरे समय में लगभग 40% तेज है।
मिस्टरमियागी

14

तानाशाही का समाधान। Is_key () पदावनत किया जाता है, 'में' का प्रयोग करें - उदात्त पाठ संपादक 3

यहाँ मैंने 'युग' नाम के शब्दकोष का एक उदाहरण लिया है -

ages = {}

# Add a couple of names to the dictionary
ages['Sue'] = 23

ages['Peter'] = 19

ages['Andrew'] = 78

ages['Karren'] = 45

# use of 'in' in if condition instead of function_name.has_key(key-name).
if 'Sue' in ages:

    print "Sue is in the dictionary. She is", ages['Sue'], "years old"

else:

    print "Sue is not in the dictionary"

6
सही है, लेकिन यह पहले से ही उत्तर दिया गया था, स्टैकवफ़्लो में आपका स्वागत है, उदाहरण के लिए धन्यवाद, हमेशा उत्तर की जांच करें!
19

@igorgue im उसे के लिए downvotes के बारे में निश्चित नहीं है। उसका उत्तर पहले से उत्तर के समान हो सकता है, लेकिन वह एक उदाहरण प्रदान करता है। पर्याप्त है कि एसओ का जवाब देने के लिए पर्याप्त नहीं है?
अक्षत अग्रवाल

14

एडम पार्किन की टिप्पणियों के साथ एलेक्स मार्टेली के प्रदर्शन परीक्षणों पर विस्तार ...

$ python3.5 -mtimeit -s'd=dict.fromkeys(range( 99))' 'd.has_key(12)'
Traceback (most recent call last):
  File "/usr/local/Cellar/python3/3.5.2_3/Frameworks/Python.framework/Versions/3.5/lib/python3.5/timeit.py", line 301, in main
    x = t.timeit(number)
  File "/usr/local/Cellar/python3/3.5.2_3/Frameworks/Python.framework/Versions/3.5/lib/python3.5/timeit.py", line 178, in timeit
    timing = self.inner(it, self.timer)
  File "<timeit-src>", line 6, in inner
    d.has_key(12)
AttributeError: 'dict' object has no attribute 'has_key'

$ python2.7 -mtimeit -s'd=dict.fromkeys(range(  99))' 'd.has_key(12)'
10000000 loops, best of 3: 0.0872 usec per loop

$ python2.7 -mtimeit -s'd=dict.fromkeys(range(1999))' 'd.has_key(12)'
10000000 loops, best of 3: 0.0858 usec per loop

$ python3.5 -mtimeit -s'd=dict.fromkeys(range(  99))' '12 in d'
10000000 loops, best of 3: 0.031 usec per loop

$ python3.5 -mtimeit -s'd=dict.fromkeys(range(1999))' '12 in d'
10000000 loops, best of 3: 0.033 usec per loop

$ python3.5 -mtimeit -s'd=dict.fromkeys(range(  99))' '12 in d.keys()'
10000000 loops, best of 3: 0.115 usec per loop

$ python3.5 -mtimeit -s'd=dict.fromkeys(range(1999))' '12 in d.keys()'
10000000 loops, best of 3: 0.117 usec per loop

अद्भुत आँकड़े, कभी-कभी निहित स्पष्ट (कम से कम दक्षता में) से बेहतर हो सकता है ...
varun

धन्यवाद, @वरुण। मैं इस जवाब के बारे में भूल गया था। मुझे इस तरह के परीक्षण अधिक बार करने की आवश्यकता है। मैं नियमित रूप से लंबे धागे पढ़ता हूं जहां लोग चीजों को करने के लिए द बेस्ट वे ™ के बारे में बहस करते हैं। लेकिन मुझे शायद ही कभी याद है कि प्रमाण प्राप्त करना कितना आसान था ।
ब्रूनो ब्रोंस्की

0

यदि आपके पास ऐसा कुछ है:

t.has_key(ew)

पायथन 3. एक्स और इसके बाद के संस्करण पर चलने के लिए इसे नीचे बदलें:

key = ew
if key not in t

6
नहीं, आपने परीक्षा को उल्टा कर दिया। t.has_key(ew)रिटर्न Trueअगर मूल्य ewसंदर्भ भी शब्दकोश में एक कुंजी है। यदि मान डिक्शनरी में नहीं है तो key not in tलौटाता Trueहै । इसके अलावा, उपनाम बहुत ही बेमानी है। सही वर्तनी है । जो पहले से बताए गए 8 साल से स्वीकृत जवाब है। key = ewif ew in t
मार्टिन पीटर्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.