Як дізнатися, чи має об’єкт атрибут у Python


1633

Чи існує спосіб у 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перед його використанням?

Відповіді:


2336

Спробуйте hasattr():

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

EDIT: Дивіться відповідь zweiterlinde нижче, хто пропонує добрі поради щодо прохання пробачення! Дуже пітонічний підхід!

Загальна практика в python полягає в тому, що, якщо властивість, ймовірно, знаходиться там більшу частину часу, просто зателефонуйте йому і нехай поширюється виняток, або захоплюйте його блоком спробу / за винятком. Це, ймовірно , буде швидше , ніж hasattr. Якщо властивість, швидше за все, там не буде, або ви не впевнені, використання hasattr, ймовірно, буде швидше, ніж повторне потрапляння в блок виключень.


19
Здається, працює і для перевірки функцій у просторі імен, наприклад: import string hasattr(string, "lower")
— riviera

15
hasattrточно так само, як використання try/ except AttributeError: docstring hasattr (в Python 2.7) говорить про те, що він використовує getattr, вловлює винятки.
— Джефф Тратнер

8
@JeffTratner: hasattrна жаль , НЕ точно такий же , як try: ... except AttributeError:в Python 2.x , так як hasattrбуде ловити все виключення . Будь ласка, дивіться мою відповідь для прикладу та простого вирішення.
— Мартін Гейслер

1
@MartinGeisler Добрий момент - це не те саме, що ловить усі винятки. Не впевнений, яка версія правильніша - насправді залежить від припущень, над якими ви працюєте, і хто називає вашу функцію. Дякуємо за уточнення.
— Джефф Тратнер

2
hasattrтакож є найкращим вибором, якщо ви розумієте, наприклад[a.property for a in list_of_as if hasattr(a, "property")]
— Рафаель Мартінс,

631

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

EAFP проти LBYL (був Re: Трохи розчарований поки що)
EAFP vs. LBYL @Code Like Pythonista: Idiomatic Python

тобто:

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

... бажано:

if hasattr(a, 'property'):
    doStuff(a.property)
else:
    otherStuff()

257
Але як ви перевіряєте, що саме саме a.property викликало AttributeError, а не щось у doStuff ()? Здається, ви цього не зробите. Я думаю, що насправді простіше просити пробачення, але багато разів це також невірно.
— jpalecek

282
EAFP здається ... божевільним. HasAttr телеграфує майбутніх програмістів з обслуговування, які ви перевіряєте на певний атрибут. Отримати виняток не говорить майбутнім програмістам нічого, і це може привести когось у кролячу нору.
— Етан Хайльман

74
@ e5: у вас є справедливий момент у цьому випадку, але у багатьох випадках EAFP є єдино правильним варіантом. Наприклад, якщо ви перевірите існування файлу, а потім відкриєте його, очікуючи, що він обов’язково існуватиме, ваш код неправильний: файл може бути видалений або перейменований між чеком і використанням. Це називається помилкою TOCTOU (Time-Of-Check-To-Time-Of-Use), і крім спричинення збоїв, також може бути джерелом вразливості безпеки.
— Макс

15
@EthanHeilman це божевільно, коли в джерелі винятків є неоднозначність, чого можна уникнути при гарному дизайні у більшості випадків. Добре шарувана структурованість логіки в рамках try / крім / нарешті загалом робить більш надійною (меншою, схильною до помилок програміста), ніж засмічення коду з попереджувальним if-чеками для кожної частини споживаючого коду. Також робить помилки дуже явними і дозволяє споживачам програмувати можливість безпосередньо мати справу з ними.
— Петро М. Ілля

64
Більшість скарг на неоднозначність є просто тому, що зразок коду погано структурований. Єдине, що всередині try:має бути спроб доступу до атрибутів; також немає причин для завершення виконання doStuff. Але все ж є певний потенціал для неоднозначності: якщо propertyце обчислена властивість замість простого атрибута, то її реалізація може підняти AttributeErrorвнутрішньо. Ось чому в майже всіх реальних ситуаціях, таких як ця, getattrє кращою hasattrабо для лову AttributeError.
— Карл Мейєр

483

Ви можете використовувати hasattr()або ловити AttributeError, але якщо ви просто хочете, щоб значення атрибуту було за замовчуванням, якщо його немає, найкращим варіантом є просто використання getattr():

getattr(a, 'property', 'default value')

14
Це вирішує обидві вищезазначені проблеми: a) Неоднозначність джерела можливого AttributeError, b) Збереження підходу EAFP.
— Петро М. Еліас

6
Це також 25% рядків коду. Звичайно, це має бути найкращим рішенням.
— fatuhoku

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-December/058498.html


Отже, ваша порада - чи не вбудовуєтесь - реалізуйте це!
— SilentGhost

Ну, не зовсім, не використовуйте вбудований IFF, який ви хочете виявити властивості. Інакше hasattr - це абсолютно добре.
— батбрат

3
hasattrвиявляє властивості взагалі просто чудово. Просто він трактує виняток у функції property-wrapped як означає, що такого атрибута не існує; пов’язана публікація списку розсилки Python - це властивість, яка створює виняток при спробі отримати доступ до неї. У всіх практичних цілях зазначений атрибут не існує, тому що він ніколи не дасть значення. Крім того, hasattrлише загалом пригнічує винятки на Py 3.1 і раніше; в 3.2+ він лише придушує (замінюючи Falseповерненням) AttributeError.
— ShadowRanger

32

Згідно з pydoc, hasattr (obj, prop) просто називає getattr (obj, prop) та ловить винятки. Отже, так само справедливо обернути доступ до атрибутів спробуйте спробувати і вилучити AttributeError, як і попередньо використовувати hasattr ().

a = SomeClass()
try:
    return a.fake_prop
except AttributeError:
    return default_value

2
Добре hasattr насправді може бути оптимізований. Наприклад, з pypy.
— odinho - Велмонт

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)

також може бути справедливим: try: a.propertyнемає необхідності в лівій частині
— Петруза

Тоді вам доведеться повторити a.property у блоці else, і це може вийти з ладу.
— Ерік Арауджо

13

Залежно від ситуації ви можете перевірити, isinstanceякий об’єкт у вас є, а потім використовувати відповідні атрибути. З впровадженням абстрактних базових класів в Python 2.6 / 3.0 цей підхід також став набагато потужнішим (в основному АВС дозволяють отримати більш складний спосіб введення качок).

Одна ситуація була б такою, що корисно було б, якщо два різні об’єкти мають атрибут з однаковою назвою, але з різним значенням. Використання лише hasattrтоді може призвести до дивних помилок.

Хороший приклад - це відмінність ітераторів від ітерабелів (див. Це питання). Ці __iter__методи в итератор і итератор мають однакові імена , але семантично абсолютно різні! Це hasattrмарно, але isinstanceразом з ABC забезпечує чисте рішення.

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


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

EDIT : Цей підхід має серйозні обмеження. Він повинен працювати, якщо об’єкт є ітерабельним . Перевірте коментарі нижче.

Якщо ви використовуєте 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

2
якщо 'змінна' у класі .__ dict__: ??
— Бен


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!

Це дозволяє вам навіть перевірити наявність атрибутів без значення.

Але! Будьте дуже обережні, щоб випадково не подати екземпляри та порівнювати undefinedкілька місць, тому що isв цьому випадку ніколи не вийде.

Оновлення:

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

undefined = NotImplemented

NotImplemented, не плутати з цим NotImplementedError, - це вбудований: він напіввідповідає наміру JS, undefinedі ви можете повторно використовувати його визначення скрізь, і воно завжди буде відповідати. Недоліки полягають у тому, що він є "truthy" в booleans, і він може виглядати дивно в журналах і стеках слідів (але ви швидко перебираєте це, коли знаєте, що це з'являється лише в цьому контексті).


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()також може бути добре використаний у поєднанні з затвердженням (щоб уникнути зайвих ifвисловлювань і зробити код більш читабельним):

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

Як сказано в іншій відповіді на SO : Асверти повинні використовуватися для тестування умов, які ніколи не повинні відбуватися. Метою є ранній збій у випадку корумпованого стану програми.


Це корисно, але може бути не завжди так. Можливо, я хотів перевірити, чи є об'єкт властивістю, а потім додати його вперше, або, можливо, мені доведеться запускати інший код для об'єктів із цим властивістю. Коли код не може продовжити, ствердження може бути нормальним. Але знову ж таки, це не завжди так. Важливим є використання hasattrне оточуючого коду.
— Лукас Габріель Санчес
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.