गैर-मौजूद विशेषताओं से निपटने के लिए hasattr () बनाम प्रयास-छोड़कर ब्लॉक


85
if hasattr(obj, 'attribute'):
    # do somthing

बनाम

try:
    # access obj.attribute
except AttributeError, e:
    # deal with AttributeError

किसे प्राथमिकता दी जानी चाहिए और क्यों?


जवाबों:


82

hasattrआंतरिक रूप से और तेजी से try/exceptब्लॉक के रूप में एक ही कार्य करता है : यह एक बहुत ही विशिष्ट, अनुकूलित, एक-कार्य उपकरण है और इस तरह, जब सामान्य रूप से लागू होता है, तो इसे बहुत सामान्य प्रयोजन के विकल्प के लिए प्राथमिकता दी जानी चाहिए।


8
सिवाय आपको अभी भी दौड़ की स्थिति को संभालने के लिए कोशिश / कैच ब्लॉक की आवश्यकता है (यदि आप थ्रेड्स का उपयोग कर रहे हैं)।
डगलस लीडर

1
या, विशेष मामला जो मुझे अभी आया है: एक django OneToOneField जिसका कोई मूल्य नहीं है: hasattr (obj, field_name) गलत लौटाता है, लेकिन field_name के साथ एक विशेषता है: यह सिर्फ एक DoNotExist त्रुटि को जन्म देता है।
मैथ्यू Schinckel

3
ध्यान दें कि पायथन 2.x में सभी अपवादोंhasattr को पकड़ा जाएगा । एक उदाहरण और तुच्छ वर्कअराउंड के लिए मेरा उत्तर देखें ।
मार्टिन गिस्लर

5
एक दिलचस्प टिप्पणी : tryयह बता सकता है कि ऑपरेशन को काम करना चाहिए । हालांकि tryइरादे हमेशा ऐसे नहीं होते हैं, यह आम है, इसलिए इसे अधिक पठनीय माना जा सकता है।
Ioannis Filippidis

88

कोई भी बेंच जो प्रदर्शन में अंतर स्पष्ट करती है?

यह आपका दोस्त है

$ python -mtimeit -s 'class C(object): a = 4
c = C()' 'hasattr(c, "nonexistent")'
1000000 loops, best of 3: 1.87 usec per loop
$ python -mtimeit -s 'class C(object): a = 4
c = C()' 'hasattr(c, "a")'
1000000 loops, best of 3: 0.446 usec per loop
$ python -mtimeit -s 'class C(object): a = 4
c = C()' 'try:
 c.a
except:
 pass'
1000000 loops, best of 3: 0.247 usec per loop
$ python -mtimeit -s 'class C(object): a = 4
c = C()' 'try:
 c.nonexistent
except:
 pass'
100000 loops, best of 3: 3.13 usec per loop
$

       |positive|negative
hasattr|  0.446 |  1.87 
try    |  0.247 |  3.13

16
दिलचस्प, मूर्त संख्या प्रदान करने के लिए +1। वास्तव में, "प्रयास" कुशल है जब इसमें सामान्य मामला होता है (यानी जब पायथन अपवाद वास्तव में असाधारण है)।
एरिक ओ लेबिगॉट

मुझे यकीन नहीं है कि इन परिणामों की व्याख्या कैसे करें। यहाँ कौन सा तेज है, और कितने द्वारा?
Stevoisiak

2
@ StevenM.Vascellaro: यदि विशेषता मौजूद है, tryतो लगभग दोगुनी तेज़ है hasattr()। यदि यह नहीं है, tryतो लगभग 1.5x से धीमी है hasattr()(और यदि विशेषता मौजूद है तो दोनों काफी धीमी हैं)। यह शायद इसलिए है, क्योंकि खुश रास्ते पर, tryशायद ही कुछ भी करता है (पायथन पहले से ही अपवादों के ओवरहेड के लिए भुगतान कर रहा है चाहे आप उनका उपयोग करें), लेकिन hasattr()इसके लिए नाम खोज और फ़ंक्शन कॉल की आवश्यकता होती है। दुखी रास्ते पर, वे दोनों को कुछ अपवाद हैंडलिंग और ए करना पड़ता है goto, लेकिन hasattr()पायथन बाइटकोड के बजाय सी में करता है।
केविन

24

एक तीसरा है, और अक्सर बेहतर, वैकल्पिक:

attr = getattr(obj, 'attribute', None)
if attr is not None:
     print attr

लाभ:

  1. getattrमार्टिन गेइजर द्वारा बताया गया बुरा अपवाद-निगलने वाला व्यवहार नहीं है - पुराने पायथन में, hasattrएक भी निगल जाएगा KeyboardInterrupt

  2. वस्तु की विशेषता होने पर आप जिस सामान्य कारण की जांच कर रहे हैं, वह यह है कि आप विशेषता का उपयोग कर सकते हैं, और यह स्वाभाविक रूप से इसकी ओर जाता है।

  3. विशेषता को परमाणु से पढ़ा जाता है, और ऑब्जेक्ट को बदलने वाले अन्य थ्रेड्स से सुरक्षित है। (हालांकि, अगर यह एक प्रमुख चिंता है, तो आप इसे एक्सेस करने से पहले ऑब्जेक्ट को लॉक करने पर विचार कर सकते हैं।)

  4. यह इससे छोटा है try/finallyऔर प्रायः इससे छोटा है hasattr

  5. एक व्यापक except AttributeErrorब्लॉक AttributeErrorsआपके द्वारा अपेक्षित एक को छोड़कर अन्य को पकड़ सकता है , जिससे भ्रामक व्यवहार हो सकता है।

  6. किसी विशेषता को एक्सेस करना एक स्थानीय वैरिएबल तक पहुँचने की तुलना में धीमा है (विशेषकर यदि यह एक सादा उदाहरण विशेषता नहीं है)। (हालांकि, ईमानदार होने के लिए, पायथन में माइक्रो-ऑप्टिमाइज़ेशन अक्सर एक मूर्ख व्यक्ति की गलती है।)

इससे सावधान रहने की एक बात यह है कि यदि आप उस मामले की परवाह करते हैं जहाँ obj.attributeकोई नहीं है, तो आपको एक अलग प्रहरी मूल्य का उपयोग करना होगा।


1
+1 - यह तानाशाही के साथ लीग में है। ('my_key', 'default_value') और अधिक व्यापक रूप से जाना जाना चाहिए

1
सामान्य उपयोग के मामले के लिए बढ़िया जहाँ आप मौजूदगी की जाँच करना चाहते हैं और डिफ़ॉल्ट मान के साथ विशेषता का उपयोग करना चाहते हैं।
dsalaj

18

मैं लगभग हमेशा उपयोग करता हूं hasattr: यह ज्यादातर मामलों के लिए सही विकल्प है।

समस्याग्रस्त मामला तब होता है जब एक वर्ग ओवरराइड करता है __getattr__: जैसे आप उम्मीद करते हैं, वैसे ही पकड़ने के बजाय सभी अपवादोंhasattr को पकड़ लेंगेAttributeError । दूसरे शब्दों में, नीचे दिया गया कोड प्रिंट होगा b: Falseभले ही ValueErrorअपवाद देखना अधिक उपयुक्त होगा :

class X(object):
    def __getattr__(self, attr):
        if attr == 'a':
            return 123
        if attr == 'b':
            raise ValueError('important error from your database')
        raise AttributeError

x = X()
print 'a:', hasattr(x, 'a')
print 'b:', hasattr(x, 'b')
print 'c:', hasattr(x, 'c')

इस प्रकार महत्वपूर्ण त्रुटि गायब हो गई है। यह पायथन 3.2 ( इश्यू 9666 ) में तय किया गया है जहां hasattrअब केवल पकड़ता है AttributeError

इस तरह एक उपयोगिता समारोह लिखने के लिए एक आसान समाधान है:

_notset = object()

def safehasattr(thing, attr):
    return getattr(thing, attr, _notset) is not _notset

यह getattrस्थिति से निपटने के लिए और इसके बाद उपयुक्त अपवाद बढ़ा सकते हैं।


2
यह भी पायथन 2.6 में थोड़ा सुधार किया गया था ताकि hasattrकम से कम पकड़ न जाए KeyboardInterruptआदि
पूली

या, इसके बजाय safehasattr, getattrयदि आप इसका उपयोग करने जा रहे हैं, तो मूल्य को एक स्थानीय चर में कॉपी करने के लिए उपयोग करें, जो आप लगभग हमेशा से हैं।
poolie

@ सपना अच्छा है, मुझे नहीं पता hasattrथा कि उस तरह सुधार किया गया था।
मार्टिन गेइस्लर

हाँ, यह अच्छा है। मुझे नहीं पता था कि या तो आज तक जब मैं किसी से बचने के लिए कहने वाला था hasattr, और जाँच करने गया था। हम कुछ अजीब bzr कीड़े जहां hasattr बस ^ C निगल लिया था।
poolie

2.7 से 3.6 के उन्नयन के दौरान समस्या का सामना कर रहा था। यह उत्तर मुझे समस्या को समझने और हल करने में मदद करता है।
कामेश जंगी

13

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

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

नीचे पंक्ति: मुझे लगता है कि यह एक दक्षता मुद्दे के बजाय एक डिजाइन और पठनीयता मुद्दा है।


1
+1 इस बात पर जोर देने के लिए कि "कोशिश" का अर्थ उन लोगों के लिए है जो कोड पढ़ते हैं। :)
एरिक ओ लेबिगॉट

5

यदि विशेषता नहीं होना कोई त्रुटि स्थिति नहीं है, तो अपवाद वाले वर्जन को हैंडल करने में समस्या होती है: यह AttributeErrors को भी पकड़ेगा जो आंतरिक रूप से आ सकता है जब obj.attribute (उदाहरण के लिए क्योंकि विशेषता एक संपत्ति है ताकि एक्सेस करने के लिए कुछ कोड का उपयोग किया जा सके)।


यह एक बड़ी समस्या है जिसे काफी हद तक नजरअंदाज किया गया है, मेरी राय में।
रिक मोनिका

5

इस विषय को सेबस्टियन विटोव्स्की द्वारा यूरोपीयन 2016 की वार्ता राइटिंग फास्ट पायथन में कवर किया गया था । यहाँ प्रदर्शन सारांश के साथ उसकी स्लाइड का प्रजनन है। वह इस चर्चा में छलांग लगाने से पहले शब्दावली शब्द का उपयोग करता है , यहाँ उस खोजशब्द को टैग करने के लिए उल्लेख के लायक है।

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

3 अनुमतियाँ या भूल गए?

# CASE 1 -- Attribute Exists
class Foo(object):
    hello = 'world'
foo = Foo()

if hasatter(foo, 'hello'):
    foo.hello
## 149ns ##

try:
    foo.hello
except AttributeError:
    pass
## 43.1 ns ##
## 3.5 times faster


# CASE 2 -- Attribute Absent
class Bar(object):
    pass
bar = Bar()

if hasattr(bar, 'hello'):
    bar.hello
## 428 ns ##

try:
    bar.hello
except AttributeError :
    pass
## 536 ns ##
## 25% slower

4

अगर यह सिर्फ एक विशेषता है जिसका आप परीक्षण कर रहे हैं, तो मैं कहूंगा कि उपयोग करें hasattr। हालाँकि, यदि आप विशेषताओं तक कई पहुँच प्राप्त कर रहे हैं जो मौजूद हो सकती हैं या नहीं भी हो सकती हैं तो tryब्लॉक का उपयोग करने से आप कुछ टाइपिंग को बचा सकते हैं।


3

मैं सुझाव दूंगा विकल्प 2. विकल्प 1 में एक दौड़ की स्थिति है यदि कोई अन्य धागा विशेषता को जोड़ या हटा रहा है।

इसके अलावा अजगर का एक मुहावरा है , कि ईएएफपी ('अनुमति से माफी मांगने में आसान') एलबीवाईएल ('आप छलांग लगाने से पहले देखो') से बेहतर है।


2

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

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

कहा कि, जैसा कि रक्स ओल्गुड बताते हैं, दूसरों के साथ संचार कोड की एक महत्वपूर्ण विशेषता है, और आप "यह एक असाधारण स्थिति है" कहकर जो कहना चाहते हैं, उसके बजाय "यह कुछ ऐसा है जो मैं होने की उम्मीद करता हूं" अधिक महत्वपूर्ण हो सकता है ।


+1 इस तथ्य पर जोर देने के लिए कि सशर्त परीक्षण की तुलना में "कोशिश" को "यह एक असाधारण स्थिति है" के रूप में व्याख्या की जा सकती है। :)
एरिक ओ लेबिगॉट

0

सबसे पहला।

कम बेहतर है। अपवाद असाधारण होने चाहिए।


5
पायथन में अपवाद बहुत आम हैं - हर forबयान के अंत में hasattrएक है, और एक का भी उपयोग करता है। हालांकि, "छोटा बेहतर है" (और "सरल बेहतर है!") लागू करें, इसलिए सरल, छोटा, अधिक विशिष्ट हैटटर वास्तव में बेहतर है।
एलेक्स मार्टेली

@ एलेक्स सिर्फ इसलिए कि पायथन पार्सर उन बयानों को बदल देता है जिनके पास 1 का मतलब यह नहीं है कि यह बहुत आम है। वहाँ एक कारण है कि उन्होंने उस सिंटैक्टिक शुगर को बनाया है: इसलिए आप ब्लॉक को छोड़कर कोशिश को टाइप करने की कमी के साथ फंस नहीं रहे हैं।
अज्ञात

यदि अपवाद असाधारण है, तो "स्पष्ट रूप से बेहतर है", और मूल पोस्टर का दूसरा विकल्प बेहतर है, मैं कहूंगा ...
एरिक ओ लेबिगॉट

0

कम से कम जब यह सिर्फ कार्यक्रम पर क्या हो रहा है, पठनीयता के मानवीय भाग को छोड़कर, आदि (जो कि वास्तव में प्रदर्शन की तुलना में अधिक समय से अधिक है (कम से कम इस मामले में - उस प्रदर्शन अवधि के साथ) जैसा कि रूही एडलर और अन्य लोगों ने बताया)।

फिर भी इसे उस नजरिए से देखा जाए, तो यह बीच का चुनाव हो जाता है

try: getattr(obj, attr)
except: ...

तथा

try: obj.attr
except: ...

चूंकि hasattrपरिणाम को निर्धारित करने के लिए बस पहले मामले का उपयोग करता है। सोच के लिए भोजन ;-)

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