Як дізнатися, чи має об’єкт атрибут у 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.