Этот вопрос уже имеет ответ здесь:
Который является лучшим способом проверить на существование атрибута?
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
Вывод:
'prop' in a.__dict__ = False hasattr(a, 'prop') = True a.prop = 3
Большую часть времени, Вы не хотите смешивать с [1 113]. Это - специальный атрибут для того, чтобы сделать специальные вещи и проверить, чтобы видеть, существует ли атрибут, является довольно приземленным.
А у общей идиомы в Python "легче попросить прощения, чем разрешение" или 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
hasattr
метод, конечно, работает также. Эту технику называют, "смотрят перед прыганием", или LBYL, если коротко.
# Cached attribute
if not hasattr(self, 'big_object'):
big_object = CreateBigObject()
self.big_object = CreateBigObject()
big_object.do_something()
(hasattr
встроенный на самом деле ведет себя странно в версиях Python до 3,2 относительно исключений - это поймает исключения, что это не было должно - но это, вероятно, не важно, так как такие исключения маловероятны. hasattr
техника также медленнее, чем [1 117], но Вы не называете ее достаточно часто для заботы, и разница не является очень большой. Наконец, hasattr
не является атомарным, таким образом, это могло бросить AttributeError
, если другой поток удаляет атрибут, но это - неправдоподобный сценарий, и необходимо будет быть очень осторожны относительно потоков так или иначе. Я не полагаю, что любое из этих трех различий стоит волнения по поводу.)
Используя [1 120] намного более просто, чем [1 121], пока все, что необходимо знать, существует ли атрибут. Большая проблема для меня - то, что техника LBYL выглядит "странной", с тех пор как Python программист я больше привык к чтению техники EAFP. При перезаписи вышеупомянутых примеров так, чтобы они использовали эти LBYL
стиль, Вы получаете код, который является или неуклюжим, напрямую неправильным, или слишком трудным для записи.
# Seems rather fragile...
if re.match('^(:?0|-?[1-9][0-9]*) И 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
, является более короткая версия [1 124].
x = getattr(self, 'x', default_value)
, Если значение по умолчанию будет дорогим для построения, то Вы закончите с чем-то вроде этого:
x = getattr(self, 'attr', None)
if x is None:
x = CreateDefaultValue()
self.attr = x
Или если None
возможное значение,
sentinel = object()
x = getattr(self, 'attr', sentinel)
if x is sentinel:
x = CreateDefaultValue()
self.attr = x
Заключение
Внутренне, getattr
и hasattr
, builtins просто используют try/except
техника (кроме записанного в C). Таким образом, они все ведут себя тот же путь, где он рассчитывает, и выбор правильного происходит из-за вопроса обстоятельств и стиля.
try/except
код EAFP будет всегда протирать некоторых программистов неправильный путь, и hasattr/getattr
, код LBYL будет раздражать других программистов. Они и корректны, и часто нет никакого действительно неопровержимого довода для выбора один или другой. (Все же другие программисты чувствуют отвращение, что Вы считали бы это нормальным, чтобы атрибут был не определен, и некоторые программисты испуганы, что даже возможно иметь неопределенный атрибут в Python.)
, 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
, является более короткая версия [1 124].
x = getattr(self, 'x', default_value)
, Если значение по умолчанию будет дорогим для построения, то Вы закончите с чем-то вроде этого:
x = getattr(self, 'attr', None)
if x is None:
x = CreateDefaultValue()
self.attr = x
Или если None
возможное значение,
sentinel = object()
x = getattr(self, 'attr', sentinel)
if x is sentinel:
x = CreateDefaultValue()
self.attr = x
Внутренне, getattr
и hasattr
, builtins просто используют try/except
техника (кроме записанного в C). Таким образом, они все ведут себя тот же путь, где он рассчитывает, и выбор правильного происходит из-за вопроса обстоятельств и стиля.
try/except
код EAFP будет всегда протирать некоторых программистов неправильный путь, и hasattr/getattr
, код LBYL будет раздражать других программистов. Они и корректны, и часто нет никакого действительно неопровержимого довода для выбора один или другой. (Все же другие программисты чувствуют отвращение, что Вы считали бы это нормальным, чтобы атрибут был не определен, и некоторые программисты испуганы, что даже возможно иметь неопределенный атрибут в Python.)
hasattr()
путь <глоток> * глоток>.
a.__dict__
ужасно, и это не работает во многих случаях. hasattr()
на самом деле попытки получить атрибут и выгоды AttributeError
внутренне, таким образом, это работает, даже если Вы определяете пользовательский __getattr__()
метод.
, Чтобы постараться не запрашивать атрибут дважды третий аргумент в пользу getattr()
мог использоваться:
not_exist = object()
# ...
attr = getattr(obj, 'attr', not_exist)
if attr is not_exist:
do_something_else()
else:
do_something(attr)
Вы могли просто использовать значение по умолчанию вместо not_exist
сигнальная метка, если это является более соответствующим в Вашем случае.
мне не нравится try: do_something(x.attr) \n except AttributeError: ..
, это могло бы скрыться AttributeError
внутренний do_something()
функция.
<глоток> * глоток> , Прежде чем Python 3.1 hasattr()
подавил все исключения (не только [1 112]), если это не желательно getattr()
, должен использоваться.
hasattr()
Pythonic способ сделать это. Изучите это, любите его.
Другой возможный путь состоит в том, чтобы проверить, является ли имя переменной в locals()
или globals()
:
if varName in locals() or in globals():
do_something()
else:
do_something_else()
я лично очень не хочу поймать исключения для проверки чего-то. Это ужасные стили. Это идентично проверке, если строка содержит только цифры тот путь:
s = "84984x"
try:
int(s)
do_something(s)
except ValueError:
do_something_else(s)
Вместо того, чтобы мягко использовать s.isdigit()
. Eww.
Очень старый вопрос, но этому действительно нужен хороший ответ. Даже для короткой программы я сказал бы, используют пользовательскую функцию!
Вот пример. Это не идеально подходит для всего приложения, но это для моего для парсинга ответов от бесчисленных API и использования Django. Легко зафиксировать для общих собственных требований.
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