Comments 16
Самый первый вопрос: стоит ли шкурка вычинки? Стоило ли проделывать такое количество работы ради получения очевидных результатов? Помоему достаточно иметь общее представление о затратах на каждый из методов.
__dict__ — поиск значения в ассоциативном массиве. Что может быть быстрее? Только прямое обращение к атрибуту, если он есть (в противном случае получим «медленное» исключение).
hasattr — реализован через getattr и исключения. Тогда очевидно, что по времени затраты будут примерно такие же как и на отдельную проверку getattr с отловом исключения (при наличие атрибута — быстро, при отсутствие — медленно).
dir — достаточно оценить время выполнения этой функции и сравнить с поиском в ассоциативном массиве.
Вот и получается, что прямой доступ (при наличии атрибута) и __dict__ — самые быстрые методы. dir — сама по себе медленная функция. В остальных случаях, будут выскакивать и ловиться исключения, а это «тяжелый» и медленный механизм. Поэтому, единственное, что заслуживает внимание — это сравнение dir и случаев с исключениями.
Кстати, а как на счет getattr(obj, attr_name, None)? Имхо, если атрибут не найден, это должно работать быстрее, чем бросать исключение.
Но в любом случае, наглядные результаты всегда надежней, чем сухая теория :)
__dict__ — поиск значения в ассоциативном массиве. Что может быть быстрее? Только прямое обращение к атрибуту, если он есть (в противном случае получим «медленное» исключение).
hasattr — реализован через getattr и исключения. Тогда очевидно, что по времени затраты будут примерно такие же как и на отдельную проверку getattr с отловом исключения (при наличие атрибута — быстро, при отсутствие — медленно).
dir — достаточно оценить время выполнения этой функции и сравнить с поиском в ассоциативном массиве.
Вот и получается, что прямой доступ (при наличии атрибута) и __dict__ — самые быстрые методы. dir — сама по себе медленная функция. В остальных случаях, будут выскакивать и ловиться исключения, а это «тяжелый» и медленный механизм. Поэтому, единственное, что заслуживает внимание — это сравнение dir и случаев с исключениями.
Кстати, а как на счет getattr(obj, attr_name, None)? Имхо, если атрибут не найден, это должно работать быстрее, чем бросать исключение.
Но в любом случае, наглядные результаты всегда надежней, чем сухая теория :)
Самый первый вопрос: стоит ли шкурка вычинки? Стоило ли проделывать такое количество работы ради получения очевидных результатов? Помоему достаточно иметь общее представление о затратах на каждый из методов.
Думаю, стоит. Я не берусь утверждать, что результаты очевидны для всех. Работы в действительно было потрачено немного. А данный тест и даёт общее представление о затратах на каждый из методов — для получения более подробной статистики уже в (полу)готовом приложении можно использовать профайлер :)
__dict__ — поиск значения в ассоциативном массиве. Что может быть быстрее? Только прямое обращение к атрибуту, если он есть...
Хммм… А разве обращение к атрибуту «напрямую» не есть поиск в
__dict__
?hasattr — реализован через getattr и исключения. Тогда очевидно, что по времени затраты будут примерно такие же как и на отдельную проверку getattr с отловом исключения (при наличие атрибута — быстро, при отсутствие — медленно).
Если бы
hasattr
был реализован как getattr
с проверкой исключения, то тогда тесты exc_getattr
и hasattr
показали бы одинаковые результаты — а это не так. Скорее, hasattr
проходит по всем __dict__
-ам, начиная от экземпляра класса и заканчивая самым «глубоким» объектом класса, осуществляя lookup во всех классах. Возможно, я ошибаюсь — нужно смотреть в исходники Python.dir — достаточно оценить время выполнения этой функции и сравнить с поиском в ассоциативном массиве.
Я взял эту функцию единственно потому, что в одном проекте, написанном доблестными индусскими программистами,
dir()
используется именно с этой целью :)Кстати, а как на счет getattr(obj, attr_name, None)? Имхо, если атрибут не найден, это должно работать быстрее, чем бросать исключение.
Идея хороша, в принципе, но в общем случае неприменима — атрибут может иметь значение None, и тогда будет непонятно, есть ли атрибут или нет.
Но в любом случае, наглядные результаты всегда надежней, чем сухая теория :)
Спасибо :)
Первую часть ответа добавил не туда :(
getattr(obj, attr_name, None) удобно использовать когда нет разницы между отсутствием атрибута и равенством атрибута None.
А вообще, практика показывает, что очень часто, оптимизация кода типа проверка наличия атрибута через getattr и Exception или поиск в __dict__, практически не дает выигрыша в скорости, так как проблемы кроются в самописных алгоритмах или кривости архитектуры :)
getattr(obj, attr_name, None) удобно использовать когда нет разницы между отсутствием атрибута и равенством атрибута None.
А вообще, практика показывает, что очень часто, оптимизация кода типа проверка наличия атрибута через getattr и Exception или поиск в __dict__, практически не дает выигрыша в скорости, так как проблемы кроются в самописных алгоритмах или кривости архитектуры :)
Ой, а таки щито ви имеете пготив самописных алгоритмов? :)
Если серьезно, не вижу в «самописности» ничего плохого — хотя бы потому, что для каждой отдельно взятой задачи можно создать такой алгоритм, который будет решать её максимально оптимально, вместо того, чтобы использовать какие-либо алгоритмы для общих случаев и накручивать «обёртки» для достижения своей цели.
А
Таким образом, видно, что в общем случае
В персональном зачете
Если серьезно, не вижу в «самописности» ничего плохого — хотя бы потому, что для каждой отдельно взятой задачи можно создать такой алгоритм, который будет решать её максимально оптимально, вместо того, чтобы использовать какие-либо алгоритмы для общих случаев и накручивать «обёртки» для достижения своей цели.
А
getattr(obj, name, None) is not None
я проверил:Групповой зачет:
getattr : 15.350072 [0 subtests failed]
Персональный зачет:
test_getattr_true_this_ca : 7.596199
test_getattr_true_parent_ca : 7.865653
test_getattr_true_this_ia : 8.003450
test_getattr_true_parent_ia : 8.811715
test_getattr_false : 22.630889
Таким образом, видно, что в общем случае
getattr
лучше прямого запроса свойства и отработку AttributeError
, но хуже hasattr
. Удивительно, но этот результат противоречит документации, потому что если hasattr
реализован через getattr
, то они должны были поменяться местами в общем рейтинге.В персональном зачете
getattr
показывает себя с лучшей стороны, чем обработка исключения, и, думаю, его можно использовать там, где его можно использовать :) — в отличии от hasattr
, он возвращает значение элемента.Да, согласен, обращение к атрибуту «напрямую» и есть поиск в __dict__. Но в первом случае должно работать быстрее из-за меньшего количества дополнительных действий, как то получение самого __dict__. Я не утверждаю, а предполагаю.
То, что hasattr реализован через getattr и исключения можно увидеть в доке: «This is implemented by calling getattr(object, name) and seeing whether it raises an exception or not.» При наличие атрибута это видно из тестов test_exc_getattr_true_this_ca и test_hasattr_true_this_ia. Но непонятно, почему так отличается результат в случае отсутствия атрибута (test_hasattr_false и test_hasattr_false).
То, что hasattr реализован через getattr и исключения можно увидеть в доке: «This is implemented by calling getattr(object, name) and seeing whether it raises an exception or not.» При наличие атрибута это видно из тестов test_exc_getattr_true_this_ca и test_hasattr_true_this_ia. Но непонятно, почему так отличается результат в случае отсутствия атрибута (test_hasattr_false и test_hasattr_false).
А насчет получения самого
__dict__
— я не помню точно, где и как, но мне встречалась ситуация, где методу __getattribute__(self, name)
передавался в качестве name
'__dict__'
.OFFTOP: Подскажите, чем делали подсветку кода? Пробовал в своей статье популярный Source Code Highlighter, но он перепахал так, что только маленькие кусочки можно использовать, а большой блок даже не запускается.
Главный вопрос: а эквивалентны ли эти методы, чтобы можно было сравнивать их скорость?
Как быть когда у вас атрибуты реально не существуют, а эмулируются через __getattr__ / __setattr__?
То есть получится, что в одном случае это будет работать быстрее, в другом существенно медленнеее, а в третьем вообще не будет.
Как быть когда у вас атрибуты реально не существуют, а эмулируются через __getattr__ / __setattr__?
То есть получится, что в одном случае это будет работать быстрее, в другом существенно медленнеее, а в третьем вообще не будет.
Ммм… я тестировал именно «рафинированные случаи» — производительность самих методов, если считать, что объект не желает странного. Методы — эквивалентны, они всегда, везде, при любых условиях (кроме
Да, переделал тест на работу с __getattribute__, запустил, жду, пока результаты будут.
dir
, но это отдельный разговор) возвращают булево значение — существует атрибут или нет. Даже при наличии __getattr__
/__getattribute__
эти методы будут работать нормально, если «перехватчики» умеют сваливаться с AttributeError() при эмуляции отсутствии атрибута.Да, переделал тест на работу с __getattribute__, запустил, жду, пока результаты будут.
Обновил статью.
перенесите, пожалуйста, в блог Python, кармы добавил
а то искал минут 10: как раз понадобилось, и ведь помню, что что-то проскакивало такое, а где искать — непонятно
а то искал минут 10: как раз понадобилось, и ведь помню, что что-то проскакивало такое, а где искать — непонятно
спасибо!
положил к себе в закладки, на будущее.
в мозг положил вывод:
иногда можно по разному, но до стадии оптимизации, т.е. почти всегда надо юзать hasattr, но оптимизировать его при желании потом иногда можно
за упоминание dir() в коде реального приложения для целей отличных от дебуга — расстреливать
положил к себе в закладки, на будущее.
в мозг положил вывод:
иногда можно по разному, но до стадии оптимизации, т.е. почти всегда надо юзать hasattr, но оптимизировать его при желании потом иногда можно
за упоминание dir() в коде реального приложения для целей отличных от дебуга — расстреливать
Sign up to leave a comment.
Ultimate benchmark пяти с половиной способов проверить наличие атрибута объекта в Python