11

Следует ли использовать 'has_key()' или 'in' для проверки наличия ключа в словарях Python?

13

Описание проблемы

У меня возникла необходимость проверить, существует ли определённый ключ в словаре в Python. Думаю, что это распространённая задача, но не могу определиться с наилучшим способом её реализации.

Вот пример словаря, с которым я работаю:

d = {'a': 1, 'b': 2}

Какой из следующих способов будет наилучшим для проверки наличия ключа 'a' в словаре d?

  1. Использовать оператор in:
'a' in d

Вывод: True

  1. Использовать метод has_key():
d.has_key('a')

Вывод: True

Проблема в том, что метод has_key() устарел в более новых версиях Python. Я хочу знать, какой способ является более предпочтительным и современным, и в каких ситуациях стоит использовать каждый из них. Большое спасибо за помощь!

5 ответ(ов)

2

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 так полезен — это не только о том, чтобы зарабатывать сотни наносекунд здесь и там!-)

0

Используйте dict.has_key(), только если ваш код должен работать на версиях Python, раннее 2.3 (когда была введена конструкция key in dict). В более современных версиях Python рекомендуется использовать if key in dict, так как это более читаемо и является стандартной практикой.

0

В одном случае использование 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.

0

Вам необходимо использовать оператор 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 является более современным и читаемым подходом для проверки наличия ключей в словаре.

0

В ответ на ваш вопрос о производительности различных методов проверки наличия ключа в словаре, можно использовать несколько интересных тестов, которые наглядно демонстрируют разницу между методами в 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() хотя и работает, но с переходом на более новые версии, рекомендуется адаптироваться к современным подходам.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь