На этом шаге мы рассмотрим особенности использования метода get().
У словарей Python есть метод get() для поиска ключа, которому передают запасное значение. Это может пригодиться в самых разных ситуациях. Приведем простой пример. Предположим, что у нас есть представленная ниже структура данных, которая ставит идентификаторы в соответствие именам пользователей:
>>> name_for_userid = {
382: 'Элис',
950: 'Боб',
590: 'Дилберт',
}
Теперь мы хотели бы использовать эту структуру данных, чтобы написать функцию greeting(), которая будет возвращать пользователю приветствие на основе его идентификатора. Наша первая реализация может выглядеть примерно так:
>>> def greeting(userid): return 'Привет, %s!' % name_for_userid[userid]
В ней представлен прямолинейный поиск в словаре. Это первая реализация технически работает - но только если идентификатор пользователя является допустимым ключом в словаре name_for_userid. Если в функцию greeting() передать недопустимый идентификатор пользователя, то она вызовет исключение:
>>> greeting(382) 'Привет, Элис!' >>> greeting(33333333) Traceback (most recent call last): . . . . KeyError: 33333333
Исключение KeyError - это совсем не тот результат, который мы хотели бы видеть. Было бы намного лучше, если бы в качестве запасного варианта функция возвращала универсальное приветствие, если идентификатор пользователя не может быть найден.
Давайте реализуем эту идею. Наш первый подход мог бы заключаться в простой проверке принадлежности в формате ключ в словаре (key in dict) и возврате приветствия по умолчанию, если идентификатор пользователя неизвестен:
>>> def greeting(userid): if userid in name_for_userid: return 'Привет, %s!' % name_for_userid[userid] else: return 'Привет всем!'
Давайте посмотрим, как эта реализация функции greeting() проявит себя с нашими предыдущими тестовыми случаями:
>>> greeting(382) 'Привет, Элис!' >>> greeting(33333333) 'Привет всем!'
Намного лучше. Мы теперь получаем универсальное приветствие для неизвестных пользователей, и мы поддерживаем персонализированное приветствие, когда допустимый идентификатор пользователя найден.
Но все равно есть простор для совершенствования. Несмотря на то что эта новая реализация дает нам ожидаемые результаты и выглядит небольшой и чистой, ее все еще можно улучшить. К этому подходу есть несколько претензий:
Этот общепринятый стиль программирования на Python исходно предполагает существование допустимых ключей или атрибутов и отлавливает исключения, если предположение оказывается ложным.
См. глоссарий Python "EAFP": https://docs.python.org/3.6/glossary.html?highlight=glossary.
Более эффективная реализация, которая следует принципам EAFP, могла бы вместо выполнения явной проверки на принадлежность ключа словарю задействовать блок try ... except, чтобы поймать исключение KeyError:
>>> def greeting(userid): try: return 'Привет, %s!' % name_for_userid[userid] except KeyError: return 'Привет всем'
Эта реализация по-прежнему верна в том, что касается наших первоначальных требований, и теперь мы устранили необходимость опрашивать словарь дважды.
Но мы до сих пор можем улучшить ее и предложить более чистое решение. В словаре Python есть метод get(), поддерживающий параметр "по умолчанию", который можно использовать в качестве запасного значения:
>>> def greeting(userid): return 'Привет, %s!' % name_for_userid.get(userid, 'всем')
См. документацию Python "dict.get()": https://docs.python.org/3/tutorial/datastructures.html#dictionaries.
Во время вызова метода get() он проверяет, существует ли заданный ключ в словаре. Если это так, то возвращается значение, соответствующее этому ключу. Если же он не существует, то вместо этого возвращается значение по умолчанию. Как вы видите, эта реализация функции greeting() по-прежнему работает как надо:
>>> greeting(950) 'Привет, Боб!' >>> greeting(333333) 'Привет, всем!'
Наша заключительная реализация функции greeting() является сжатой, чистой и использует средства только из стандартной библиотеки Python. Поэтому для этой конкретной ситуации такое решение является наилучшим.
На следующем шаге мы подитожим изученный материал.