속성의 존재를 확인하는 가장 좋은 방법은 무엇입니까?
이 질문에 이미 답변이 있습니다.
- 객체에 Python 13 답변 의 속성이 있는지 확인하는 방법
속성의 존재를 확인하는 더 좋은 방법은 무엇입니까?
Jarret Hardie 가이 답변을 제공했습니다.
if hasattr(a, 'property'):
a.property
이 방법으로도 할 수 있습니다.
if 'property' in a.__dict__:
a.property
일반적으로 한 접근 방식이 다른 접근 방식보다 더 많이 사용됩니까?
속성이 존재하는지 확인하기 만하는 것이 아니기 때문에 "최상의"방법 은 없습니다. 항상 더 큰 프로그램의 일부입니다. 몇 가지 올바른 방법과 하나의 주목할만한 잘못된 방법이 있습니다.
잘못된 방법
if 'property' in a.__dict__:
a.property
다음은이 기술의 실패를 보여주는 데모입니다.
class A(object):
@property
def prop(self):
return 3
a = A()
print "'prop' in a.__dict__ =", 'prop' in a.__dict__
print "hasattr(a, 'prop') =", hasattr(a, 'prop')
print "a.prop =", a.prop
산출:
a .__ dict__의 'prop'= False hasattr (a, 'prop') = True a.prop = 3
대부분의 경우 __dict__
. 특별한 일을하기위한 특별한 속성이고 속성이 존재하는지 확인하는 것은 상당히 평범합니다.
EAFP 방식
파이썬의 일반적인 관용구는 "허가보다 용서를 구하기가 더 쉽다"또는 줄여서 EAFP입니다. 이 관용구를 사용하는 많은 Python 코드를 볼 수 있으며 속성 존재를 확인하기위한 용도 만이 아닙니다.
# Cached attribute
try:
big_object = self.big_object
# or getattr(self, 'big_object')
except AttributeError:
# Creating the Big Object takes five days
# and three hundred pounds of over-ripe melons.
big_object = CreateBigObject()
self.big_object = big_object
big_object.do_something()
이것은 존재하지 않을 수있는 파일을 여는 것과 똑같은 관용구입니다.
try:
f = open('some_file', 'r')
except IOError as ex:
if ex.errno != errno.ENOENT:
raise
# it doesn't exist
else:
# it does and it's open
또한 문자열을 정수로 변환합니다.
try:
i = int(s)
except ValueError:
print "Not an integer! Please try again."
sys.exit(1)
옵션 모듈을 가져 오는 중 ...
try:
import readline
except ImportError:
pass
LBYL 방식
hasattr
방법은 물론, 너무 작동합니다. 이 기술을 "도약하기 전에보기"또는 줄여서 LBYL이라고합니다.
# Cached attribute
if not hasattr(self, 'big_object'):
big_object = CreateBigObject()
self.big_object = CreateBigObject()
big_object.do_something()
( hasattr
은 그게 안 예외를 잡을 것입니다 - - 내장 실제로 예외와 관련하여 3.2 이전의 파이썬 버전에 이상하게 동작합니다. 그러나 그러한 예외 가능성이 있기 때문에 이것은 아마도 무관 인 hasattr
기술은 또한보다 느린 것입니다 try/except
,하지만 주의 할만큼 자주 호출하지 마십시오. 그 차이는 그다지 크지 않습니다. 마지막으로 hasattr
원 자성이 아니므로 AttributeError
다른 스레드가 속성을 삭제하면 던질 수 있습니다 . 그러나 이것은 매우 어려운 시나리오이므로 어쨌든 쓰레드에 대해 매우 조심해야합니다. 저는이 세 가지 차이점에 대해 걱정할 가치가 없다고 생각하지 않습니다.)
속성이 존재하는지 여부 만 알면되므로 사용 hasattr
은보다 훨씬 간단 try/except
합니다. 저에게 큰 문제는 LBYL 기술이 "이상하게"보인다는 것입니다. 파이썬 프로그래머로서 저는 EAFP 기술을 읽는 데 더 익숙하기 때문입니다. LBYL
스타일 을 사용하도록 위의 예제를 다시 작성하면 서 투르거나 완전히 부정확하거나 작성하기 너무 어려운 코드가 생성됩니다.
# Seems rather fragile...
if re.match('^(:?0|-?[1-9][0-9]*)$', s):
i = int(s)
else:
print "Not an integer! Please try again."
sys.exit(1)
그리고 LBYL은 때때로 완전히 부정확합니다.
if os.path.isfile('some_file'):
# At this point, some other program could
# delete some_file...
f = open('some_file', 'r')
옵션 모듈을 가져 오기위한 LBYL 함수를 작성하고 싶다면 내 손님이 되십시오. 함수가 전체 괴물처럼 들립니다.
getattr 방법
기본값 만 필요한 getattr
경우은보다 짧은 버전의 try/except
.
x = getattr(self, 'x', default_value)
기본값을 구성하는 데 비용이 많이 드는 경우 다음과 같은 결과를 얻게됩니다.
x = getattr(self, 'attr', None)
if x is None:
x = CreateDefaultValue()
self.attr = x
Or if None
is a possible value,
sentinel = object()
x = getattr(self, 'attr', sentinel)
if x is sentinel:
x = CreateDefaultValue()
self.attr = x
Conclusion
Internally, the getattr
and hasattr
builtins just use try/except
technique (except written in C). So they all behave the same way where it counts, and picking the right one is due to a matter of circumstances and style.
The try/except
EAFP code will always rub some programmers the wrong way, and the hasattr/getattr
LBYL code will irk other programmers. They're both correct, and there's often no truly compelling reason to pick one or the other. (Yet other programmers are disgusted that you would consider it normal for an attribute to be undefined, and some programmers are horrified that it's even possible to have an undefined attribute in Python.)
hasattr()
is the way*.
a.__dict__
is ugly and it doesn't work in many cases. hasattr()
actually tries to get attribute and catches AttributeError
internally so it works even if you define custom __getattr__()
method.
To avoid requesting the attribute twice the third argument for getattr()
could be used:
not_exist = object()
# ...
attr = getattr(obj, 'attr', not_exist)
if attr is not_exist:
do_something_else()
else:
do_something(attr)
You could just use a default value instead of not_exist
sentinel if it is more appropriate in your case.
I don't like try: do_something(x.attr) \n except AttributeError: ..
it might hide AttributeError
inside do_something()
function.
*Before Python 3.1 hasattr()
suppressed all exceptions (not only AttributeError
) if it is not desirable getattr()
should be used.
hasattr()
is the Pythonic way to do it. Learn it, love it.
Other possible way is to check whether the variable name is in locals()
or globals()
:
if varName in locals() or in globals():
do_something()
else:
do_something_else()
I personally hate to catch exceptions in order to check something. It looks and feels ugly. It's identical to checking if a string contains only digits that way:
s = "84984x"
try:
int(s)
do_something(s)
except ValueError:
do_something_else(s)
Instead of gently using s.isdigit()
. Eww.
Very old question but it really needs a good answer. For even a short program, I'd say use a custom function!
Here's an example. It's not perfect for all application but it is for mine, for parsing responses from countless APIs and using Django. It's easy to fix for everyone's own requirements.
from django.core.exceptions import ObjectDoesNotExist
from functools import reduce
class MultipleObjectsReturned(Exception):
pass
def get_attr(obj, attr, default, asString=False, silent=True):
"""
Gets any attribute of obj.
Recursively get attributes by separating attribute names with the .-character.
Calls the last attribute if it's a function.
Usage: get_attr(obj, 'x.y.z', None)
"""
try:
attr = reduce(getattr, attr.split("."), obj)
if hasattr(attr, '__call__'):
attr = attr()
if attr is None:
return default
if isinstance(attr, list):
if len(attr) > 1:
logger.debug("Found multiple attributes: " + str(attr))
raise MultipleObjectsReturned("Expected a single attribute")
else:
return str(attr[0]) if asString else attr[0]
else:
return str(attr) if asString else attr
except AttributeError:
if not silent:
raise
return default
except ObjectDoesNotExist:
if not silent:
raise
return default
'Program Tip' 카테고리의 다른 글
SBT : 기본이 아닌 프로젝트의 기본 클래스에 대한 명령 줄 '실행'을 시작합니다. (0) | 2020.11.26 |
---|---|
브라우저 뒤로 버튼으로 되돌아 가면 양식의 모든 필드를 지 웁니다. (0) | 2020.11.26 |
NodeJS 요청의 모듈 gzip 응답 본문을 어떻게 ungzip (압축 해제)합니까? (0) | 2020.11.26 |
If string is not null or empty else에 대한 라이너 1 개 (0) | 2020.11.26 |
사전이 목록보다 훨씬 빠른 이유는 무엇입니까? (0) | 2020.11.26 |