파이썬 용서 대 권한 및 오리 입력


44

파이썬에서는 종종 "권한 요청"(유형 / 조건 확인) 대신 "용서하기"(예외 잡기)가 더 좋다고 들었습니다. 파이썬에서 오리 타이핑을 시행하는 것과 관련하여, 이것은

try:
    x = foo.bar
except AttributeError:
    pass
else:
    do(x)

보다 나은 또는 나쁜

if hasattr(foo, "bar"):
    do(foo.bar)
else:
    pass

성능, 가독성, "pythonic"또는 기타 중요한 요소와 관련하여?


17
세 번째 옵션이 있습니다. 아무것도하지 말고 바없이 foo를 버그로 취급하십시오
jk.

hasattr내부적으로 정확한 시도 / 캐치로 구현 된 청각을 기억 합니다. 그것이 사실이라면 특정하지 (? 그것은 어쩌면 내가 생각하고 그렇지 않은 것, 특성에 다르게 행동 것입니다 getattr..)
Izkata

@ Izkata : 구현은hasattr C-API와 동등한 것을 사용하지만 getattr( True성공 False하지 않으면 반환 ) C에서 예외를 처리하는 것이 훨씬 빠릅니다.
Martijn Pieters

2
martijn의 답변을 수락했지만 속성을 설정하려고하면 set / set이없는 속성 일 수 있으므로 try / catch를 사용하는 것이 좋습니다.이 경우 hasattr이 true입니다. 이지만 여전히 AttributeError가 발생합니다.
darkfeline

답변:


60

실제로 예외가 얼마나 자주 발생한다고 생각 하느냐에 달려 있습니다.

제 생각에는 두 가지 접근 방식 모두 최소한 가독성과 파이썬 성 측면에서 똑같이 유효합니다. 그러나 객체의 90 %에 속성 이 없는 경우 bar두 접근 방식간에 성능 차이가 뚜렷하게 나타납니다.

>>> import timeit
>>> def askforgiveness(foo=object()):
...     try:
...         x = foo.bar
...     except AttributeError:
...         pass
... 
>>> def askpermission(foo=object()):
...     if hasattr(foo, 'bar'):
...         x = foo.bar
... 
>>> timeit.timeit('testfunc()', 'from __main__ import askforgiveness as testfunc')
2.9459929466247559
>>> timeit.timeit('testfunc()', 'from __main__ import askpermission as testfunc')
1.0396890640258789

그러나 객체의 90 %에 속성 있으면 테이블이 설정됩니다.

>>> class Foo(object):
...     bar = None
... 
>>> foo = Foo()
>>> timeit.timeit('testfunc(foo)', 'from __main__ import askforgiveness as testfunc, foo')
0.31336188316345215
>>> timeit.timeit('testfunc(foo)', 'from __main__ import askpermission as testfunc, foo')
0.4864199161529541

따라서 성능 관점에서 상황에 가장 적합한 접근 방식을 선택해야합니다.

결국, timeit모듈을 전략적으로 사용하는 것이 가장 파이썬적인 일일 수 있습니다.


1
몇 주 전에 나는 다음과 같은 질문을했다 : programmers.stackexchange.com/questions/161798/… 나는 느슨하게 타이핑 된 언어로 타입 체크를 추가로해야하는지에 대해 물었다. 당신이 가진 걸 알아
Tulains Córdova

@ user1598390 : 유형이 균일 할 것으로 예상 되는 API를 정의 할 때는 몇 가지 테스트를 수행해야합니다. 대부분은 그렇지 않습니다. 이것은 패러다임에 대한 규칙을 전체적으로 도출 할 수없는 특정 영역입니다.
Martijn Pieters

모든 심각한 시스템 개발에는 API 정의가 포함됩니다. 컴파일러가 컴파일 타임에 유형을 확인하기 때문에 코드를 적게 작성해야하기 때문에 유형 엄격한 언어가 가장 좋습니다.
Tulains Córdova

1
@GarethRees : 테스트 할 함수에 인수를 전달하는 답변의 후반부에 대한 패턴을 설정합니다.
Martijn Pieters

1
에 대해서는 hasattr실제로 어쨌든 후드 아래에서 try-except와 동등한 C-api를 수행합니다.
user2357112

11

파이썬에서는 종종 파이썬 방식으로 더 나은 성능을 얻습니다. 다른 언어의 경우 흐름 제어에 예외를 사용하는 것은 일반적으로 예외가 특별한 오버 헤드를 유발하기 때문에 끔찍한 아이디어로 간주됩니다. 그러나이 기술은 파이썬에서 명시 적으로 승인되었으므로 인터프리터는이 유형의 코드에 최적화되어 있습니다.

모든 성능 관련 질문과 마찬가지로 코드를 프로파일 링하는 것이 유일한 방법입니다. 두 버전을 모두 작성하고 어느 버전이 더 빨리 실행되는지 확인하십시오. 내 경험상 "Python way"가 일반적으로 가장 빠른 방법입니다.


3

필자는 성능이 부차적 인 문제라고 생각합니다. 문제가 발생하면 프로파일 러는 실제 병목 현상에 초점을 맞출 수 있도록 도와줍니다. 이는 불법적 인 주장을 처리하는 방법 일 수도 있고 아닐 수도 있습니다.

반면에 가독성과 단순성은 항상 주요 관심사입니다. 여기에는 어려운 규칙이 없으며 판단 만 사용하십시오.

이것은 보편적 인 문제이지만 환경 또는 언어 별 규칙이 적합합니다. 예를 들어, 파이썬에서는 일반적으로 예상되는 속성을 사용하여 가능한 AttributeError가 호출자에게 도달하도록하는 것이 좋습니다.


-1

정확성 측면에서 예외 처리는 갈 길이라고 생각합니다 (그러나 때로는 hasattr () 접근 방식을 직접 사용합니다). hasattr ()에 의존하는 기본적인 문제는 코드 계약 위반이 자동 실패로 바뀐다는 것입니다 (이것은 존재하지 않는 속성을 던지지 않는 JavaScript의 큰 문제입니다).


3
귀하의 답변은 다른 사람들이 이미 언급 한 것 이상으로 많은 것을 추가하지 않는 것 같습니다. 다른 사이트와 달리 프로그래머는 답변의 이유 를 설명하는 답변을 기대합니다 . 당신은 침묵 실패 문제로 좋은 점을 만지지 만 반드시 정의를 제공하지는 마십시오. 다음을 읽으면 도움이 될 것입니다. programmers.stackexchange.com/help/how-to-answer

내가 한 마지막 답변은 너무 광범위하다는 비판을 받았습니다. 나는 짧고 간결하게 시도 할 것이라고 생각했습니다.
Joe
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.