Comments 9
В теории всё неплохо. Но часть иллюстрирующих примеров откровенно неудачные.
1. Вот это совсем не `просто и не очевидно`. В добавок к мусорной переменной seen_namesещё и посадили баг. Потерялась сортированность processed_names:
names = ["john", "jane", "", "john", "doe"]
processed_names = []
seen_names = set()
for name in names:
if name and name not in seen_names:
processed_names.append(name.upper())
seen_names.add(name)
Оригинальный код не эталон читабельности, но для программиста на python понятен, хотя с list comprehensions становится более идиоматичным
processed_names = list(set(name.upper() for name in names if name))2. Вот это тоже очень криво для python
def get_passed_students(student_records):
approved_students = []
for record in student_records:
grade = record[1]
name = record[0]
if grade > 10:
approved_students.append(name)
return approved_studentsвсю эту простыню лучше заменить чем-то более читабельным
def get_passed_students_names(student_records):
return [name for (name, grade) in student_records if grade > 10]Статья для тех, кто книгу не читал?
list(set(map(lambda name: name.upper(), filter(lambda name: name, names))))Этот код ужасен.
Но то, что вы предложили это далего не лучший подход, а реализация вообще с ошибкой.
Pythonic код будет
list({name.upper() for name in names if name})Дальше читать не стал, я не довeряю вашей компетенции после превого примера.
Хорошее, полезное напоминание. Приятно было прочитать, если не брать во внимание достаточно вырожденные примеры.
Я бы ещё добавил:
Не забывать type hints там, где нет очевидной логики на уровне линтеров.
Не забывать про NamedTuples, dataclass для группировки предметных данных.
Обратить внимание на логику разделения модулей. Там есть нетривиальные ходы.
Про list comprehension ничего не сказано, а стоило бы.
На самом деле, все трюки и не перечислить в одной статье. Python даёт очень много мощных инструментов, преимущество которых не всегда лежит на поверхности.
black, flake8, isort заменяются одним Ruff.
В 101 раз повторено одно и то же с упрощёнными примерами, а таким важным вещам, как типизация, уделена одна строчка между делом. data.get("username") почему-то не попадает под критикуемую далее категорию магических констант. Хотя не раз в одном продукте видел user_name в одном месте и username в другом. И где тот интересный баланс между YAGNI и обкладыванием dataclass'ами всего подряд? Или выбор между NamedTuple и dataclass? Или вообще протоколом?
Из интересного увидел только использование ветки else в try: впервые встречаю среди прочитанного кода, и очень интересная рекомендация по использованию: вынести в try только потенциально опасный кусок. А как же читаемость? Код друг за другом - все понятно, ожидаемые исключения в конце ветками - тоже понятно. А эта конструкция смотрится странно, даже интересно, что вдохновило дизайнеров языка на такое. Какая реальная польза от else вместо описания happy-path и обработки разных исключений разом без детализации, кто же там споткнулся?
Хотя не раз в одном продукте видел
user_nameв одном месте иusernameв другом.
Я такие стараюсь на модельниые классы переписать.
Или выбор между NamedTuple и dataclass
Если тупла хватает, то его, если нет то датакласс. Если сериализация то можно Pydantic подключить. Ни один из перечисленных и даже простые кортежи не подходят для больших нагрузок, так-что внутри можно выбирать не особо заморачиваясь.
Код, за который не стыдно: Практика чистописания для начинающих Python-разработчиков