Задача 1. Разминочная, но в ней подвох
Первая задача всегда разминочная, это тест "свой-чужой". Не решил - на выход, сурово, жестоко, как есть. Решил криво - будь добр переделать или хотя бы покажи собеседнику, что видишь ошибки. А лучше сразу решить красиво, отказоустойчиво, задействуя современный Python. В этой статье я привожу пример такой задачи и даю три варианта решения: новичковое, нормальное и отличное. Условие задачи и код с комментариями в статье.
Постановка задачи
Есть фамилия, имя и отчество. Нужно получить ФИО: был Сидоров Иван Семенович, должен получиться Сидоров И. С. И просто, и сложно одновременно:
✅ Если знать распаковку, split, f-строки, то решить не составит труда;
✅ Если писать 💩-код с индексами частей ФИО и индексами букв, то можно, в лучшем случае, запутаться. В худшем - код упадет.
Здесь разбираю код новичка, хороший код и лучший код, учитывающий все нюансы.
Код новичка
Новичок пишет так, что лишь бы работало. Я не говорю, что это плохо. Лучше написать что-то, чем не написать ничего. Тем не менее, следует стремиться пользоваться возможностями Python на 100%.
# Задача 1. Фамилия и имя
poet = "Пушкин Александр Сергеевич"
# джун
name_parts = poet.split()
short_name = name_parts[0] + " " + name_parts[1][0].upper() + " " + \
"." + name_parts[2][0].upper() + "."
print(short_name)
Недостатки видите сами:
✅ магические числа, индексы, сложение строк. Да, работает, но выглядит несовременно;
✅ проблема даже не в том, что код выглядит неряшливо. Проблема в том, что если отчества нет, то код упадет. Т.е. в этом коде сразу скрыта бомба замедленного действия.
Код получше
Если абстрагироваться от проблемы с недостаточным или избыточным числом частей имени (т.е. не 3, а больше или меньше), то более интересный код мог быть таким:
# Задача 1. Фамилия и имя (middle - senior)
poet = "Пушкин Александр Сергеевич"
first, middle, last = poet.split()
short_name = f"{first} {middle[0].upper()}. {last[0].upper()}."
print(short_name)
Чем код лучше:
✅ исчезли магические числа, т.е. нулевая, первая и вторая часть имени. Да, остались индексы букв [0], но в части имени всегда будут буквы, поэтому в этом плане код не упадет. Напомню, что split() игнорирует пустые строки.
✅ код стал более читаемый. Т.е. нет многократных сложений, которые только запутывают.
😡 все еще есть недостатки. Например, если split() вернет больше 3-х частей имени, то код упадет. Если частей имени меньше двух, то мы также получим мало приятного. Как минимум, проблема будет в обращении к пустому месту в last[0].upper().
Код на синьора
Код выше страдал от отсутствия универсальности. Если в имени только 2 части (имя и фамилия), то код выше не сработал бы. А если бы частей было больше, скажем Квинт Помпей Сенецио Росций Мурена Целий Секст Юлий Фронтин, то код выше не вывел бы остальные части имени через точку. Код ниже лишен этих недостатков, но он посложнее, чем то, что мы писали до этого.
from functools import reduce
def get_short_name(long_name: str) -> str:
first_name, *other = long_name.split()
first_letters = [s[0].upper() for s in other]
initials = reduce(lambda res, x: res + x + ". ", first_letters, "")
return f"{first_name} {initials}"
print(get_short_name("Эркюль Савиньен Сирано де Бержерак"))
print(get_short_name("Пушкин Александр Сергеевич"))
print(get_short_name("Пушкин Александр"))
print(get_short_name("Пушкин"))
Какие приемы здесь используются?
✅ распаковка в переменное число аргументов other . Таким образом решается проблема неизвестного количества частей имени;
✅ списковые включения или list comprehensions позволяют быстро получить первые буквы каждого слова после первого. Предполагаем, что фамилия идет первой. Конечно в реальности это не совсем так, но для данной задачи такое упрощение допускается;
✅ Функция reduce из модуля functools , которая повзоляет "свернуть" список элементов в одно значение. Такой подход использовать не обязательно, можно создать строку с инициалами в цикле.
✅ prints после функции демонстрируют работу функции для разного числа частей имени.
Видео-версия на Youtube
Данная задача разбирается в видео на Youtube, есть тайм-коды.
Код и исходные данные
Код и исходные данные к нему доступны по ссылке