if hasattr(obj, 'attribute'):
# do somthing
vs
try:
# access obj.attribute
except AttributeError, e:
# deal with AttributeError
어느 것이 선호되어야하며 그 이유는 무엇입니까?
답변:
hasattr
내부적으로 그리고 신속하게 try/except
블록 과 동일한 작업을 수행합니다 . 매우 구체적이고 최적화 된 단일 작업 도구이므로 적용 가능한 경우 매우 범용적인 대안보다 선호되어야합니다.
hasattr
합니다 모든 예외 잡기 파이썬 2.x 또는 3.0에서을 예제와 간단한 해결 방법 은 내 대답 을 참조하십시오 .
성능 차이를 보여주는 벤치가 있습니까?
시간이 너의 친구 야
$ 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.5 배 느립니다 hasattr()
(둘 다 속성이 존재하는 경우보다 상당히 느립니다). 이것은 아마도 행복한 길에서 try
거의 아무것도하지 않지만 (Python은 사용 여부에 관계없이 이미 예외 오버 헤드를 지불하고 있음) hasattr()
이름 조회 및 함수 호출이 필요 하기 때문일 것입니다 . 불행한 경로에서 둘 다 예외 처리와 a를 수행해야 goto
하지만 hasattr()
Python 바이트 코드가 아닌 C에서 수행합니다.
세 번째, 종종 더 나은 대안이 있습니다.
attr = getattr(obj, 'attribute', None)
if attr is not None:
print attr
장점 :
getattr
나쁜없는 예외 삼키는 동작 마틴 GEISER 지적 - 옛날 비단뱀에, hasattr
심지어 삼키는 것이다 KeyboardInterrupt
.
객체에 속성이 있는지 확인하는 일반적인 이유는 속성을 사용할 수 있도록하기위한 것이며, 이는 당연히 속성으로 이어집니다.
속성은 원자 적으로 읽히고 객체를 변경하는 다른 스레드로부터 안전합니다. (하지만 이것이 중요한 문제라면 객체에 액세스하기 전에 잠그는 것이 좋습니다.)
보다 짧고 try/finally
종종보다 짧습니다 hasattr
.
넓은 except AttributeError
블록 AttributeErrors
은 예상 한 블록이 아닌 다른 블록을 잡을 수 있으며, 이로 인해 혼란스러운 동작이 발생할 수 있습니다.
속성에 액세스하는 것은 지역 변수에 액세스하는 것보다 느립니다 (특히 일반 인스턴스 속성이 아닌 경우). (솔직히 말해서 Python의 마이크로 최적화는 종종 바보의 심부름입니다.)
주의 obj.attribute
해야 할 사항은 None으로 설정된 경우에 신경을 쓰면 다른 센티넬 값을 사용해야한다는 것입니다.
나는 거의 항상 사용합니다 hasattr
: 대부분의 경우에 올바른 선택입니다.
문제가있는 경우는 클래스가 오버라이드 (override) 할 때이다 __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
상황을 처리하고 적절한 예외를 발생시킬 수 있습니다.
safehasattr
, 단지 사용 getattr
당신은 거의 항상있는, 그것을 사용하려고하는 경우 로컬 변수의 값을 복사합니다.
hasattr
개선 된 줄은 몰랐 습니다.
hasattr
확인하러 갔다. hasattr이 방금 ^ C를 삼킨 재미있는 bzr 버그가있었습니다.
예를 들어 함수에 대한 두 명의 호출자가있는 경우 하나는 속성이있는 객체를 제공하고 다른 하나는 속성이없는 객체를 제공하는 경우와 같이 함수가 의도적으로 속성 이 없는 객체를 허용할지 여부에 따라 달라집니다 .
속성이없는 객체를 얻을 수있는 유일한 경우가 오류 때문인 경우 더 느리더라도 예외 메커니즘을 사용하는 것이 좋습니다. 더 깔끔한 디자인이라고 믿기 때문입니다.
결론 : 효율성 문제 라기보다는 디자인과 가독성 문제라고 생각합니다.
이 주제는 Sebastian Witowski가 쓴 EuroPython 2016 Talk Writing faster Python 에서 다루었습니다 . 다음은 성능 요약과 함께 그의 슬라이드를 재현 한 것입니다. 그는 또한 이 토론을 시작하기 전에 용어 Look을 사용 하며 여기에서 해당 키워드에 태그를 지정할 가치가 있습니다.
속성이 실제로 누락 된 경우 용서를 구하는 것이 권한을 요청하는 것보다 느립니다. 따라서 경험적으로 속성이 누락되거나 예측할 수있는 다른 문제가있을 가능성이 매우 높다는 것을 알고있는 경우 권한 요청 방식을 사용할 수 있습니다. 그렇지 않으면 코드가 대부분의 경우 코드를 읽을 수 있다고 예상하면
# 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
실용적인 관점에서 보면 대부분의 언어에서 조건을 사용하는 것은 예외를 처리하는 것보다 항상 훨씬 빠릅니다.
현재 함수 외부에 존재하지 않는 속성의 경우를 처리하려면 예외가 더 좋은 방법입니다. 조건부 대신 예외를 사용하고 싶을 수있는 표시기는 조건부에서 플래그를 설정하고 현재 작업을 중단하고 다른 곳에서이 플래그를 확인하고 이에 따라 조치를 취한다는 것입니다.
즉, Rax Olgud가 지적했듯이 다른 사람과의 의사 소통은 코드의 중요한 속성 중 하나이며 "이것은 제가 예상하는 일입니다."라기보다는 "이것은 예외적 인 상황입니다"라고 말하고 싶은 것이 더 중요 할 수 있습니다. .
첫번째.
짧을수록 좋습니다. 예외는 예외적이어야합니다.
for
문장 끝에 하나가 있고 hasattr
하나도 사용합니다. 그러나 "짧을수록 좋습니다"(그리고 "단순할수록 좋습니다"!) 적용하십시오. 따라서 더 간단하고 짧고 구체적인 hasattr가 실제로 바람직합니다.