Как узнать, есть ли у объекта атрибут в Python

1636

Есть ли способ в Python, чтобы определить, есть ли у объекта какой-либо атрибут? Например:

>>> a = SomeClass()
>>> a.someProperty = value
>>> a.property
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: SomeClass instance has no attribute 'property'

Как вы можете определить, aесть ли атрибут propertyперед его использованием?

Лукас Габриэль Санчес
источник

Ответы:

2344

Попробуй hasattr():

if hasattr(a, 'property'):
    a.property

РЕДАКТИРОВАТЬ: Смотрите ответ zweiterlinde ниже, который предлагает хороший совет о том, как просить прощения! Очень питонический подход!

Общая практика в python заключается в том, что если свойство, скорее всего, присутствует там большую часть времени, просто вызовите его и либо распространите исключение, либо перехватите его с помощью блока try / исключением. Это, вероятно, будет быстрее, чем hasattr. Если свойство, скорее всего, не будет присутствовать большую часть времени, или вы не уверены, использование hasattrбудет, вероятно, быстрее, чем повторное попадание в блок исключения.

Джаррет Харди
источник
19
Кажется, работает и для проверки функций в пространстве имен, например: import string hasattr(string, "lower")
riviera
15
hasattrточно так же, как использование try/ except AttributeError: строка документации hasattr (в Python 2.7) говорит, что она использует getattr для ловли исключений вручную.
Джефф Тратнер
8
@JeffTratner: hasattrк сожалению, это не совсем то же самое, что и try: ... except AttributeError:в Python 2.x, так hasattrкак перехватит все исключения . Пожалуйста, посмотрите мой ответ для примера и простого обходного пути.
Мартин Гайслер
632

Как ответил Джаррет Харди , все hasattrполучится. Я хотел бы добавить, однако, что многие в сообществе Python рекомендуют стратегию «проще просить прощения, чем разрешения» (EAFP), а не «смотреть перед прыжком» (LBYL). Смотрите эти ссылки:

EAFP против LBYL (пока Re: немного разочарован)
EAFP против LBYL @Code Как Pythonista: Идиоматический Python

то есть:

try:
    doStuff(a.property)
except AttributeError:
    otherStuff()

... предпочтительнее:

if hasattr(a, 'property'):
    doStuff(a.property)
else:
    otherStuff()
zweiterlinde
источник
259
Но как проверить, что именно a.property вызвал AttributeError, а не что-то в doStuff ()? Кажется, ты не. Я думаю, что действительно проще просить прощения, но часто это также неправильно.
jpalecek
286
EAFP кажется ... безумным. HasAttr передает телеграфным сообщениям будущим программистам, которые проверяют наличие определенного атрибута. Получение исключения ничего не говорит будущим программистам и может привести кого-нибудь в кроличью нору.
Итан Хейлман,
74
@ e5: в этом случае вы справедливы, но во многих случаях EAFP - единственный правильный вариант. Например, если вы проверите наличие файла, а затем откроете его, ожидая, что он обязательно будет существовать, ваш код неверен: файл может быть удален или переименован между проверкой и использованием. Это называется ошибкой TOCTOU (время проверки-время-использования) и, помимо того, что вызывает сбои, также может быть источником уязвимостей безопасности.
Макс
15
@EthanHeilman, это безумие только тогда, когда в источнике исключения есть двусмысленность, которую можно избежать при хорошем дизайне в большинстве случаев. Хорошо структурированное структурирование логики внутри try / Кроме / Наконец, как правило, обеспечивает более надежную (менее подверженную ошибкам программиста) логику, чем засорение кода упреждающими проверками if для каждого фрагмента потребляющего кода. Также делает ошибки очень явными и дает программистам возможность иметь дело с ними напрямую.
Питер М. Элиас
64
Большинство жалоб на неоднозначность здесь просто потому, что пример кода плохо структурирован. Единственная вещь внутри try:должна быть попыткой доступа к атрибуту; нет никаких причин, чтобы обернуть выполнение doStuffтакже. Тем не менее, существует некоторая возможность для двусмысленности: если propertyвычисляемое свойство вместо простого атрибута, его реализация может возникнуть AttributeErrorвнутри. Вот почему почти во всех реальных ситуациях, подобных этой, getattrпредпочтительнее либо hasattrловить, либо ловить AttributeError.
Карл Мейер
485

Вы можете использовать hasattr()или поймать AttributeError, но если вам действительно нужно значение атрибута со значением по умолчанию, если его там нет, лучшим вариантом будет просто использовать getattr():

getattr(a, 'property', 'default value')
Карл Мейер
источник
14
Это решает обе вышеупомянутые проблемы: а) Неоднозначность источника возможной ошибки AttributeError, б) Сохранение подхода EAFP.
Питер М. Элиас
6
Это также 25% строк кода. Конечно, это должно быть лучшим решением.
фатухоку
16
Это лучшее решение «если вы действительно хотите, чтобы значение атрибута было установлено по умолчанию». Хотя я полагаю, что этого действительно хотят многие, когда говорят, что хотят определить, присутствует ли атрибут, ФП фактически запросил последний, поэтому разумно, чтобы прямые ответы на этот вопрос (hasattr, AttributeError) были перечислены выше. ,
Карл Мейер
41

Я думаю, что вы ищете, это hasattr . Тем не менее, я бы порекомендовал что-то подобное, если вы хотите обнаружить свойства Python -

try:
    getattr(someObject, 'someProperty')         
except AttributeError:
    print "Doesn't exist"
else
    print "Exists"

Недостатком здесь является то, что ошибки атрибутов в __get__коде свойств также отлавливаются.

В противном случае,

if hasattr(someObject, 'someProp'):
    #Access someProp/ set someProp
    pass

Документы: http://docs.python.org/library/functions.html
Предупреждение
. Моя рекомендация заключается в том, что hasattr не определяет свойства.
Ссылка: http://mail.python.org/pipermail/python-dev/2005-De December/ 058498.html

batbrat
источник
3
hasattrобнаруживает свойства в целом просто отлично. Просто он обрабатывает возникновение исключения в propertyфункции -wrapped как означающее, что такого атрибута не существует; Связанный пост списка рассылки Python о свойстве, которое вызывает исключение при попытке доступа к нему. Для всех практических целей указанный атрибут не существует, потому что он никогда не будет создавать значение. Кроме того, hasattrподавляет только исключения вообще на Py 3.1 и ранее; в 3.2+ он только подавляет (замена на Falseвозврат) AttributeError.
ShadowRanger
32

Согласно pydoc, hasattr (obj, prop) просто вызывает getattr (obj, prop) и перехватывает исключения. Таким образом, столь же правильно обернуть доступ к атрибуту оператором try и перехватить AttributeError, как и использовать hasattr () заранее.

a = SomeClass()
try:
    return a.fake_prop
except AttributeError:
    return default_value
Джордан Льюис
источник
2
Ну, на самом деле hasattr может быть оптимизирован. Например, с pypy.
Одино - Вельмонт
6
+1. Это даже безопаснее, чем hasattrпри SomeClassпереопределении, __getattr__поскольку hasattrперехватывает все исключения в Python 2.x, а не так, AttributeErrorкак вы ожидаете. Это было исправлено в Python 3.2 - смотрите мой другой ответ для простого обходного пути.
Мартин Гайслер
24

Я хотел бы предложить избежать этого:

try:
    doStuff(a.property)
except AttributeError:
    otherStuff()

Пользователь @jpalecek упомянул это: если AttributeErrorпроисходит внутри doStuff(), вы потерялись.

Может быть, этот подход лучше:

try:
    val = a.property
except AttributeError:
    otherStuff()
else:
    doStuff(val)
Maico
источник
13

В зависимости от ситуации вы можете проверить, isinstanceкакой у вас объект, а затем использовать соответствующие атрибуты. С введением абстрактных базовых классов в Python 2.6 / 3.0 этот подход также стал намного более мощным (в основном ABC допускают более изощренный способ типизации утки).

Одна из этих ситуаций была бы полезной, если бы два разных объекта имели атрибут с одинаковым именем, но с разным значением. Использование только hasattrможет привести к странным ошибкам.

Хорошим примером является различие между итераторами и итераторами (см. Этот вопрос). Эти __iter__методы в итератор и итератор имеют одинаковые имена , но семантически совершенно разные! Так hasattrбесполезно, но isinstanceвместе с АВС обеспечивает чистое решение.

Однако я согласен, что в большинстве ситуаций hasattrподход (описанный в других ответах) является наиболее подходящим решением.

nikow
источник
13

Надеюсь, вы ожидаете hasattr (), но старайтесь избегать hasattr () и, пожалуйста, предпочитайте getattr (). getattr () быстрее, чем hasattr ()

используя hasattr ():

 if hasattr(a, 'property'):
     print a.property

то же самое здесь я использую getattr, чтобы получить свойство, если нет свойства, оно не возвращает

   property = getattr(a,"property",None)
    if property:
        print property
Джанартанан Раму
источник
11

РЕДАКТИРОВАТЬ : этот подход имеет серьезные ограничения. Это должно работать, если объект является повторяемым . Пожалуйста, проверьте комментарии ниже.

Если вы используете Python 3.6 или выше, как я, есть удобная альтернатива, чтобы проверить, имеет ли объект определенный атрибут:

if 'attr1' in obj1:
    print("attr1 = {}".format(obj1["attr1"]))

Однако я не уверен, какой сейчас самый лучший подход. использование hasattr(), использование getattr()или использование in. Комментарии приветствуются.

Найяк
источник
6
inКлючевое слово работает для проверки итерируемых типов. Например, 'foo' in Noneвыдает ошибку TypeError: argument of type 'NoneType' is not iterable. Исправление состоит в том, чтобы проверить, является ли тип повторяемым перед использованием in. После исправления для крайних случаев, таких как не повторяемый тип, вам, вероятно, лучше использовать, hasattr()поскольку он предназначен для обработки крайних случаев.
Сет Дифли
3
Это не имеет ничего общего с доступом к атрибутам. Понятия не имею, как за это проголосовали. Единственное сходство, которое имеет атрибут доступа, заключается в том, что вы используете его dictв качестве «легковесного объекта», подобного дизайну объектов JavaScript, но большинство обычных классов не будет поддерживать это в целом (получение варианта ошибки, упомянутой @SethDifley) ,
ShadowRanger
6

Вот очень интуитивный подход:

if 'property' in dir(a):
    a.property
Алек Аламеддин
источник
1

Это очень просто, просто используйте dir(объект.)
Это вернет список всех доступных функций и атрибутов объекта.

Шон Христиане
источник
1

Другой возможный вариант, но это зависит от того , что вы подразумеваете , прежде чем :

undefined = object()

class Widget:

    def __init__(self):
        self.bar = 1

    def zoom(self):
        print("zoom!")

a = Widget()

bar = getattr(a, "bar", undefined)
if bar is not undefined:
    print("bar:%s" % (bar))

foo = getattr(a, "foo", undefined)
if foo is not undefined:
    print("foo:%s" % (foo))

zoom = getattr(a, "zoom", undefined)
if zoom is not undefined:
    zoom()

вывод:

bar:1
zoom!

Это позволяет вам даже проверять None-значимые атрибуты.

Но! Будьте очень осторожны, вы не случайно создадите и сравните undefinedнесколько мест, потому что isв этом случае они никогда не сработают.

Обновить:

из-за того, о чем я предупреждал в предыдущем абзаце, имея несколько неопределенных, которые никогда не совпадают, я недавно немного изменил этот шаблон:

undefined = NotImplemented

NotImplemented, не путать с NotImplementedError, является встроенным: он почти соответствует цели JS, undefinedи вы можете использовать его определение везде, и оно всегда будет совпадать. Недостатки в том, что он «правдив» в логических значениях и может выглядеть странно в журналах и трассировках стека (но вы быстро справляетесь с этим, когда знаете, что он появляется только в этом контексте).

JL Peyret
источник
0

Вы можете проверить, objectсодержит ли атрибут, используяhasattr встроенный метод.

Например, если ваш объект aи вы хотите проверить атрибутstuff

>>> class a:
...     stuff = "something"
... 
>>> hasattr(a,'stuff')
True
>>> hasattr(a,'other_stuff')
False

Сама сигнатура метода hasattr(object, name) -> boolозначает, что objectимеет атрибут, который передается второму аргументу, hasattrчем он дает логическое значение, Trueили в Falseсоответствии с наличием nameатрибута в объекте.

Деванг Падияр
источник
0

hasattr()это правильный ответ. Что я хочу добавить, так это то, что он hasattr()также может быть использован в сочетании с assert (чтобы избежать ненужных ifутверждений и сделать код более читабельным):

assert hasattr(a, 'property'), 'object lacks property' 

Как указано в другом ответе на SO : утверждения должны использоваться для проверки условий, которые никогда не должны возникать. Целью является ранний сбой в случае повреждения программы.

FMF
источник
Это полезно, но не всегда так. Возможно, я хотел проверить, есть ли у объекта свойство, а затем добавить его в первый раз, или, возможно, мне нужно запустить другой код для объектов с этим свойством. Когда код не может продолжить, утверждение может быть в порядке. Но опять же, это не всегда так. Важным моментом является использование hasattrне окружающего кода.
Лукас Габриэль Санчес