if hasattr(obj, 'attribute'):
# do somthing
बनाम
try:
# access obj.attribute
except AttributeError, e:
# deal with AttributeError
किसे प्राथमिकता दी जानी चाहिए और क्यों?
जवाबों:
hasattr
आंतरिक रूप से और तेजी से try/except
ब्लॉक के रूप में एक ही कार्य करता है : यह एक बहुत ही विशिष्ट, अनुकूलित, एक-कार्य उपकरण है और इस तरह, जब सामान्य रूप से लागू होता है, तो इसे बहुत सामान्य प्रयोजन के विकल्प के लिए प्राथमिकता दी जानी चाहिए।
hasattr
को पकड़ा जाएगा । एक उदाहरण और तुच्छ वर्कअराउंड के लिए मेरा उत्तर देखें ।
try
यह बता सकता है कि ऑपरेशन को काम करना चाहिए । हालांकि try
इरादे हमेशा ऐसे नहीं होते हैं, यह आम है, इसलिए इसे अधिक पठनीय माना जा सकता है।
कोई भी बेंच जो प्रदर्शन में अंतर स्पष्ट करती है?
यह आपका दोस्त है
$ 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
try
तो लगभग दोगुनी तेज़ है hasattr()
। यदि यह नहीं है, try
तो लगभग 1.5x से धीमी है hasattr()
(और यदि विशेषता मौजूद है तो दोनों काफी धीमी हैं)। यह शायद इसलिए है, क्योंकि खुश रास्ते पर, try
शायद ही कुछ भी करता है (पायथन पहले से ही अपवादों के ओवरहेड के लिए भुगतान कर रहा है चाहे आप उनका उपयोग करें), लेकिन hasattr()
इसके लिए नाम खोज और फ़ंक्शन कॉल की आवश्यकता होती है। दुखी रास्ते पर, वे दोनों को कुछ अपवाद हैंडलिंग और ए करना पड़ता है goto
, लेकिन hasattr()
पायथन बाइटकोड के बजाय सी में करता है।
एक तीसरा है, और अक्सर बेहतर, वैकल्पिक:
attr = getattr(obj, 'attribute', None)
if attr is not None:
print attr
लाभ:
getattr
मार्टिन गेइजर द्वारा बताया गया बुरा अपवाद-निगलने वाला व्यवहार नहीं है - पुराने पायथन में, hasattr
एक भी निगल जाएगा KeyboardInterrupt
।
वस्तु की विशेषता होने पर आप जिस सामान्य कारण की जांच कर रहे हैं, वह यह है कि आप विशेषता का उपयोग कर सकते हैं, और यह स्वाभाविक रूप से इसकी ओर जाता है।
विशेषता को परमाणु से पढ़ा जाता है, और ऑब्जेक्ट को बदलने वाले अन्य थ्रेड्स से सुरक्षित है। (हालांकि, अगर यह एक प्रमुख चिंता है, तो आप इसे एक्सेस करने से पहले ऑब्जेक्ट को लॉक करने पर विचार कर सकते हैं।)
यह इससे छोटा है try/finally
और प्रायः इससे छोटा है hasattr
।
एक व्यापक except AttributeError
ब्लॉक AttributeErrors
आपके द्वारा अपेक्षित एक को छोड़कर अन्य को पकड़ सकता है , जिससे भ्रामक व्यवहार हो सकता है।
किसी विशेषता को एक्सेस करना एक स्थानीय वैरिएबल तक पहुँचने की तुलना में धीमा है (विशेषकर यदि यह एक सादा उदाहरण विशेषता नहीं है)। (हालांकि, ईमानदार होने के लिए, पायथन में माइक्रो-ऑप्टिमाइज़ेशन अक्सर एक मूर्ख व्यक्ति की गलती है।)
इससे सावधान रहने की एक बात यह है कि यदि आप उस मामले की परवाह करते हैं जहाँ obj.attribute
कोई नहीं है, तो आपको एक अलग प्रहरी मूल्य का उपयोग करना होगा।
मैं लगभग हमेशा उपयोग करता हूं 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
स्थिति से निपटने के लिए और इसके बाद उपयुक्त अपवाद बढ़ा सकते हैं।
safehasattr
, getattr
यदि आप इसका उपयोग करने जा रहे हैं, तो मूल्य को एक स्थानीय चर में कॉपी करने के लिए उपयोग करें, जो आप लगभग हमेशा से हैं।
hasattr
था कि उस तरह सुधार किया गया था।
hasattr
, और जाँच करने गया था। हम कुछ अजीब bzr कीड़े जहां hasattr बस ^ C निगल लिया था।
मैं कहूंगा कि यह इस बात पर निर्भर करता है कि क्या आपका फ़ंक्शन ऑब्जेक्ट को डिज़ाइन द्वारा विशेषता के बिना स्वीकार कर सकता है , उदाहरण के लिए यदि आपके पास फ़ंक्शन के दो कॉलर हैं, तो एक विशेषता के साथ एक ऑब्जेक्ट प्रदान करता है और दूसरा इसके बिना ऑब्जेक्ट प्रदान करता है।
यदि एकमात्र मामला जहां आपको विशेषता के बिना एक ऑब्जेक्ट मिलेगा, तो कुछ त्रुटि के कारण, मैं अपवाद तंत्र का उपयोग करने की सिफारिश करूंगा, भले ही यह धीमा हो सकता है, क्योंकि मेरा मानना है कि यह एक क्लीनर डिजाइन है।
नीचे पंक्ति: मुझे लगता है कि यह एक दक्षता मुद्दे के बजाय एक डिजाइन और पठनीयता मुद्दा है।
यदि विशेषता नहीं होना कोई त्रुटि स्थिति नहीं है, तो अपवाद वाले वर्जन को हैंडल करने में समस्या होती है: यह AttributeErrors को भी पकड़ेगा जो आंतरिक रूप से आ सकता है जब obj.attribute (उदाहरण के लिए क्योंकि विशेषता एक संपत्ति है ताकि एक्सेस करने के लिए कुछ कोड का उपयोग किया जा सके)।
इस विषय को सेबस्टियन विटोव्स्की द्वारा यूरोपीयन 2016 की वार्ता राइटिंग फास्ट पायथन में कवर किया गया था । यहाँ प्रदर्शन सारांश के साथ उसकी स्लाइड का प्रजनन है। वह इस चर्चा में छलांग लगाने से पहले शब्दावली शब्द का उपयोग करता है , यहाँ उस खोजशब्द को टैग करने के लिए उल्लेख के लायक है।
यदि विशेषता वास्तव में गायब है, तो माफी के लिए भीख माँगना अनुमतियों की तुलना में धीमा होगा। इसलिए अंगूठे के एक नियम के रूप में आप अनुमति के तरीके का उपयोग कर सकते हैं यदि आपको पता है कि यह बहुत संभावना है कि विशेषता गायब हो जाएगी या अन्य समस्याएं जो आप भविष्यवाणी कर सकते हैं। अन्यथा यदि आप उम्मीद करते हैं कि कोड के परिणामस्वरूप अधिकांश समय पठनीय कोड होगा
# 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
मैं सुझाव दूंगा विकल्प 2. विकल्प 1 में एक दौड़ की स्थिति है यदि कोई अन्य धागा विशेषता को जोड़ या हटा रहा है।
इसके अलावा अजगर का एक मुहावरा है , कि ईएएफपी ('अनुमति से माफी मांगने में आसान') एलबीवाईएल ('आप छलांग लगाने से पहले देखो') से बेहतर है।
एक व्यावहारिक दृष्टिकोण से, अधिकांश भाषाओं में एक सशर्त का उपयोग हमेशा अपवाद को संभालने की तुलना में हमेशा तेज होगा।
यदि आप वर्तमान फ़ंक्शन के बाहर मौजूद किसी विशेषता के मामले को संभालना चाहते हैं, तो अपवाद बेहतर तरीका है। एक संकेतक जिसे आप सशर्त के बजाय एक अपवाद का उपयोग करना चाह सकते हैं, यह है कि सशर्त केवल एक ध्वज सेट करता है और वर्तमान संचालन को रोक देता है, और कुछ और इस ध्वज की जांच करता है और उसके आधार पर कार्रवाई करता है।
कहा कि, जैसा कि रक्स ओल्गुड बताते हैं, दूसरों के साथ संचार कोड की एक महत्वपूर्ण विशेषता है, और आप "यह एक असाधारण स्थिति है" कहकर जो कहना चाहते हैं, उसके बजाय "यह कुछ ऐसा है जो मैं होने की उम्मीद करता हूं" अधिक महत्वपूर्ण हो सकता है ।
सबसे पहला।
कम बेहतर है। अपवाद असाधारण होने चाहिए।
for
बयान के अंत में hasattr
एक है, और एक का भी उपयोग करता है। हालांकि, "छोटा बेहतर है" (और "सरल बेहतर है!") लागू करें, इसलिए सरल, छोटा, अधिक विशिष्ट हैटटर वास्तव में बेहतर है।
कम से कम जब यह सिर्फ कार्यक्रम पर क्या हो रहा है, पठनीयता के मानवीय भाग को छोड़कर, आदि (जो कि वास्तव में प्रदर्शन की तुलना में अधिक समय से अधिक है (कम से कम इस मामले में - उस प्रदर्शन अवधि के साथ) जैसा कि रूही एडलर और अन्य लोगों ने बताया)।
फिर भी इसे उस नजरिए से देखा जाए, तो यह बीच का चुनाव हो जाता है
try: getattr(obj, attr)
except: ...
तथा
try: obj.attr
except: ...
चूंकि hasattr
परिणाम को निर्धारित करने के लिए बस पहले मामले का उपयोग करता है। सोच के लिए भोजन ;-)