ProgramingTip

존재하지 않는 속성을 처리하기 위해 hasattr () 대 try-except 블록

bestdevel 2020. 10. 13. 08:09
반응형

존재하지 않는 속성을 처리하기 위해 hasattr () 대 try-except 블록


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

vs

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

어느 것이 선호되어야하며 왜 그럴까요?


hasattr내부적으로 그리고 신속하게 try/except블록 과 동일한 작업을 수행합니다 . 매우 다양하고 최적화 된 단일 작업 도구 적용 가능한 경우 매우 범용적인 대안보다 선호되어야합니다.


성능 차이를 비교할 수 있습니까?

시간이 너의 친구 야

$ 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

세 번째, 종종 더 나은 대안이 있습니다.

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

장점 :

  1. getattr나쁜없는 예외 삼키는 동작 마틴 GEISER 지적 -옛날 비단뱀에, hasattr심지어 삼키는 것 KeyboardInterrupt입니다.

  2. 이는 명백한 속성을 확인하는 이유는 속성을 사용할 수 있습니다.

  3. 속성은 원자를 적으로 읽히고 변경하는 것으로부터 안전합니다. (하지만 아주 중요한 문제라면 객체에 액세스하기 전에 잠그는 것이 좋습니다.)

  4. 보다 짧고 try/finally종종 보다 짧습니다 hasattr.

  5. 넓은 except AttributeError블록 AttributeErrors은 예상 한 블록이 아닌 다른 블록을 잡을 수있어 혼란스러운 동작을 유발할 수 있습니다.

  6. 속성에 액세스하는 것은 지역 변수에 액세스하는 것보다 느립니다 (일반 인스턴스 속성이 아닌 경우). (솔직히 말해서 Python의 마이크로 최적화는 종종 바보의 심부름입니다.)

주의 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')

따라서 중요한 오류가 사라. 이 문제는 Python 3.2 ( issue9666 )에서 수정hasattr 현재 AttributeError.

쉬운 해결 방법은 다음과 같은 유틸리티 함수를 작성하는 것입니다.

_notset = object()

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

이것은 getattr상황을 처리하고 예외를 발생시킨다.


나는 당신의 함수가 속성없이 획득을 받아 들일 수 있는지에 달려 말할 것입니다. 를 들어 함수 예에, 대한 두 명의 호출자가있는 경우 하나는 속성이있는 object-를 제공하고 다른 하나는 속성이없는 object-를 제공하는 경우와 같이 함수가 의도적으로 .

속성이없는 경우를 얻을 수있는 유일한 경우에 사용하는 것이 좋습니다. 더 중요한 디자인이라고 믿기 때문입니다.

결론 : 효율성 문제 라기보다는 디자인과 가독성 문제라고 생각합니다.


테스트하는 속성 중 하나 인 경우 사용라고 말하고 싶습니다 hasattr. 그러나 존재하거나 존재하지 않을 수있는 속성에 여러 액세스를 수행하는 경우 try블록 을 사용하면 입력 입력을 줄일 수 있습니다.


속성이 없는 것이 오류 조건 아닌 경우 예외 처리 변형에 문제가 있습니다. obj.attribute에 액세스 할 때 내부적으로 올 수있는 AttributeErrors도 catch합니다 (예를 들어 속성은 속성이므로 액세스하면 일부 코드가 호출 됨).


옵션 2를 제안합니다. 다른 스레드가 속성을 추가하거나 제거하는 경우 옵션 1에 경쟁 조건이 있습니다.

또한 파이썬은이 관용구를 EAFP가 ( '쉽게 허락보다 용서를 물어')가 LBYL ( '보기 전에 도약')보다 더 낫다는 것을.


실용적인 관점에서 볼 때 대부분의 언어에서 조건부를 사용하는 것은 예외를 처리하는 것보다 항상 훨씬 빠릅니다.

현재 함수 외부에 존재하지 않는 속성의 경우를 처리하려면 예외가 더 좋은 방법입니다. 조건부 대신 예외를 사용하고 싶을 수있는 표시기는 조건부에서 플래그를 설정하고 현재 작업을 중단하고 다른 곳에서이 플래그를 확인하고 이에 따라 조치를 취한다는 것입니다.

즉, Rax Olgud가 지적했듯이 다른 사람과의 의사 소통은 코드의 중요한 속성 중 하나이며 "이것은 내가 예상하는 일입니다."라기보다는 "이것은 예외적 인 상황입니다"라고 말하고 싶은 것이 더 중요 할 수 있습니다. .


이 주제는 Sebastian Witowski 의 EuroPython 2016 강연에서 더 빠른 Python 작성 에서 다루었습니다 . 다음은 성능 요약과 함께 그의 슬라이드를 재현 한 것입니다. 그는 또한 이 토론을 시작하기 전에 용어 Look을 사용 하며 여기에서 해당 키워드에 태그를 지정할 가치가 있습니다.

속성이 실제로 누락 된 경우 용서를 구하는 것이 권한을 요청하는 것보다 느립니다. 따라서 경험적으로 속성이 누락되거나 예측할 수있는 다른 문제가있을 가능성이 매우 높다는 것을 알고있는 경우 권한 요청 방식을 사용할 수 있습니다. 그렇지 않으면 코드가 대부분의 경우 코드를 읽을 수 있다고 예상하면

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

첫번째.

짧을수록 좋습니다. 예외는 예외적이어야합니다.


적어도 프로그램에서 일어나는 일에 달려있을 때, 가독성의 인간 부분을 배제하는 등 (실제로 대부분의 경우 성능보다 더 중요합니다 (적어도이 경우에는-성능 범위에서), Roee Adler와 다른 사람들이 지적했듯이).

그럼에도 불구하고 그 관점에서 보면, 그것은 선택의 문제가됩니다.

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

try: obj.attr
except: ...

이후 hasattr바로 첫 번째 경우를 사용하여 결과를 확인합니다. 생각할 거리 ;-)

참고 URL : https://stackoverflow.com/questions/903130/hasattr-vs-try-except-block-to-deal-with-non-existent-attributes

반응형