Следует ли использовать 'has_key()' или 'in' для проверки наличия ключа в словарях Python?
Описание проблемы
У меня возникла необходимость проверить, существует ли определённый ключ в словаре в Python. Думаю, что это распространённая задача, но не могу определиться с наилучшим способом её реализации.
Вот пример словаря, с которым я работаю:
d = {'a': 1, 'b': 2}
Какой из следующих способов будет наилучшим для проверки наличия ключа 'a'
в словаре d
?
- Использовать оператор
in
:
'a' in d
Вывод: True
- Использовать метод
has_key()
:
d.has_key('a')
Вывод: True
Проблема в том, что метод has_key()
устарел в более новых версиях Python. Я хочу знать, какой способ является более предпочтительным и современным, и в каких ситуациях стоит использовать каждый из них. Большое спасибо за помощь!
5 ответ(ов)
in
безусловно выигрывает, как в элегантности (и не является устаревшим;-) так и в производительности. Например:
$ python -mtimeit -s'd=dict.fromkeys(range(99))' '12 in d'
10000000 loops, best of 3: 0.0983 usec per loop
$ python -mtimeit -s'd=dict.fromkeys(range(99))' 'd.has_key(12)'
1000000 loops, best of 3: 0.21 usec per loop
Хотя следующее наблюдение не всегда верно, вы заметите, что обычно в Python быстреее решение также более элегантно и питонично. Именно поэтому -mtimeit
так полезен — это не только о том, чтобы зарабатывать сотни наносекунд здесь и там!-)
Используйте dict.has_key()
, только если ваш код должен работать на версиях Python, раннее 2.3 (когда была введена конструкция key in dict
). В более современных версиях Python рекомендуется использовать if key in dict
, так как это более читаемо и является стандартной практикой.
В одном случае использование in
действительно может существенно снизить производительность.
Если вы применяете in
к контейнеру с амортизированной сложностью O(1), который реализует только методы __getitem__
и has_key()
, но не имеет __contains__
, это приведет к тому, что поиск с O(1) превратится в O(N), поскольку оператор in
будет использовать линейный поиск через __getitem__
.
Решение очевидно и тривиально:
def __contains__(self, x):
return self.has_key(x)
Таким образом, реализовав метод __contains__
, вы сможете восстановить ожидаемую производительность при использовании оператора in
.
Вам необходимо использовать оператор in
, так как метод has_key()
устарел в Python. Вот пример работы со словарем под названием ages
:
ages = {}
# Добавляем несколько имен в словарь
ages['Sue'] = 23
ages['Peter'] = 19
ages['Andrew'] = 78
ages['Karren'] = 45
# Используем 'in' в условии вместо метода has_key()
if 'Sue' in ages:
print("Сью есть в словаре. Ей", ages['Sue'], "лет")
else:
print("Сью нет в словаре")
В этом примере мы проверяем, содержится ли 'Sue' в словаре ages
, и выводим соответствующее сообщение. Использование in
является более современным и читаемым подходом для проверки наличия ключей в словаре.
В ответ на ваш вопрос о производительности различных методов проверки наличия ключа в словаре, можно использовать несколько интересных тестов, которые наглядно демонстрируют разницу между методами в Python 2.7 и 3.5.
Для начала, стоит упомянуть, что метод has_key()
больше не поддерживается в Python 3.x, как показывает следующий вывод:
$ python3.5 -mtimeit -s'd=dict.fromkeys(range( 99))' 'd.has_key(12)'
Traceback (most recent call last):
...
AttributeError: 'dict' object has no attribute 'has_key'
В Python 2.7 этот метод все еще доступен и показывает производительность около 0.0872 мкс за цикл для словаря с 99 элементами:
$ python2.7 -mtimeit -s'd=dict.fromkeys(range( 99))' 'd.has_key(12)'
10000000 loops, best of 3: 0.0872 usec per loop
Проверяя производительность метода has_key()
с увеличением числа элементов (1999), время выполнения остается в пределах 0.0858 мкс:
$ python2.7 -mtimeit -s'd=dict.fromkeys(range(1999))' 'd.has_key(12)'
10000000 loops, best of 3: 0.0858 usec per loop
В Python 3.5 предпочтительнее использовать оператор in
для проверки наличия ключа, который показывает значительно лучшие результаты (0.031 и 0.033 мкс для 99 и 1999 элементов соответственно):
$ python3.5 -mtimeit -s'd=dict.fromkeys(range( 99))' '12 in d'
10000000 loops, best of 3: 0.031 usec per loop
$ python3.5 -mtimeit -s'd=dict.fromkeys(range(1999))' '12 in d'
10000000 loops, best of 3: 0.033 usec per loop
Сравним это с использованием d.keys()
, который оказывается менее эффективным (0.115 и 0.117 мкс для этих же наборов данных):
$ python3.5 -mtimeit -s'd=dict.fromkeys(range( 99))' '12 in d.keys()'
10000000 loops, best of 3: 0.115 usec per loop
$ python3.5 -mtimeit -s'd=dict.fromkeys(range(1999))' '12 in d.keys()'
10000000 loops, best of 3: 0.117 usec per loop
Таким образом, можно сделать вывод, что для проверки наличия ключа в словаре в Python 3.x следует использовать оператор in
, так как он наиболее оптимален по производительности. В Python 2.7 метод has_key()
хотя и работает, но с переходом на более новые версии, рекомендуется адаптироваться к современным подходам.
Итерация по словарям с использованием циклов 'for'
Создание словаря (dict) из отдельных списков ключей и значений
Преобразование списка словарей в DataFrame pandas
Почему использовать dict.get(key) вместо dict[key]?
Получить ключ по значению в словаре