Друзья, всех приветствую!
Меня зовут Дмитрий и я являюсь инструктором и соавтором курсов Основы Python и Python для Пентестера академии Codeby.
Это вторая часть серии статей, где я рассказываю о распространённых ошибках учеников курса и показываю способы исправлениях таких ситуаций. Часть 1.
1. Длинный if
Как многие из вас знают, оператор if в python используется для проверки условий. У этого оператора существуют блоки ветвления elif и else (хотя может использоваться и без них). Зачастую, когда в программах требуются сразу все элементы этой конструкции, код условия может выглядеть довольно объёмно.
Предположим, нам нужно написать небольшую программу, которая будет запрашивать у пользователя название столицы и возвращать континент, на котором расположен этот город.
Попробуем реализовать решение “в лоб”: создаём кортеж, где в каждой строке перечислим названия столиц, соответствующих континентов. Запрашиваем ввод пользователя, приводя строку к нужному регистру, и условием if проверяем по очереди все строки кортежа:
Подобное решение будет отчасти рабочим (если мы введём пробел или пустую строку, то получим ошибочный результат), и слушатели чаще всего используют подобный подход к решению заданий.
Но существует несколько рекомендаций по оптимизации и упрощению кода.
Первое, что я рекомендую - это поместить проверку негативного варианта в самое начало условия. Тем самым мы сразу показываем, какой ситуации хотим избежать.
Описать эту проверку можно разными способами и, думаю, многие сразу захотят использовать цикл, но я бы предложил вариант проще: проверим длину, чтобы избежать ошибки пустой строки, и “склеим” кортеж в одну строку, а через оператор in проверим вхождение:
Читая этот код, мы сразу видим, что строка длиной меньше двух символов и строка не из кортежа capitals нам не подойдут. Для этого не придётся просматривать всё условие до конца.
Вторым действием я призываю активнее использовать вложенность условий. То есть расположить проверки на своих уровнях вложенности.
В нашем примере есть две проверки: первая - для проверки наличия строки в кортеже, вторая - для проверки совпадения. В таком случае разумно будет создать как раз два уровня вложенности:
Логика кода не поменялась, но визуально работать с ним будет гораздо проще - разные уровни проверки помогают сориентироваться в условиях.
Можно пойти ещё дальше и не описывать последнее условие, отправив его в else
Обе описанные рекомендации - использование разных уровней вложенности и перемещение негативного варианта в начало положительно скажутся на читабельности кода. Активнее используйте их в ваших программах.
2. Использование словаря и if
Довольно часто использование длинного условия можно заменить словарём и условием проверки вхождения. Представьте, что нам нужно получить коды ответов сайтов и для каждого блока кодов создать определённое цветовое оформление.
Первое что приходит в голову, это создать цикл и условие:
Условие уже состоит из 4 ветвлений, а представьте, насколько оно разрастётся, если нам захочется оформить свои подгруппы, чтобы отличить, например, 400 код от 404?
В подобной ситуации разумнее будет создать новый объект - словарь, поместив в ключи те самые коды:
Теперь нам остаётся создать одно условие проверки вхождения кода в ключах словаря и дальше получать код по этому самому ключу:
Мало того, что мы смогли сделать код компактнее, так ещё и расширение его будет гораздо проще - добавить нужный элемент в словарь гораздо быстрее, чем несколько строк ветвления.
Опять же воспользуемся рекомендацией выше по расположению негативного условия в самом начале. Можно поступить ещё проще, указав не полный код, а только первую цифру в ключах, но тогда придётся получать эту цифру через деление или приведение к строке.
Как видите, подобных подход с использованием словаря в ряде случаев, делает код значительно проще и понятнее.
В версии python 3.10 была
3. Моржовый оператор.
Заканчивая тему условий, нельзя не сказать про введённый в версии 3.8 моржовый оператор.
Конструкция := (похожая на глаза и клыки моржа) позволяет прямо в условии if создать переменную и там же проверить её.
То есть вместо
можно оформить код сразу в строке условия:
Как видно из примера выше, мы можем вызывать нужные методы сразу у моржового выражения.
Обратите внимание, что выражение с моржом нужно оборачивать скобками, если в следующих частях условия мы хотим продолжать работать с ним. Иначе могут возникнуть досадные ошибки логики:
Из-за того, что мы явно не указали, какой именно объект хотим получить в переменную, python стал выполнять выражение как обычно справа налево: запросил строку у пользователя и сравнил её со строкой 'password':
а результат этого выражения уже поместил в переменную.
В итоге, если пароль будет правильным, в переменной окажется True, иначе - False.
Если же мы хотим получить не булево значение, а введённую строку, убираем в скобки выражение с моржом
Тем самым мы поместили результат вызова функции input в переменную, а условие проверит равенство введённой строки и строки 'password'. Обращайте на этот момент особое внимание!
Ну а так как цикл while - это такое же условие if, только выполняющееся до тех пор, пока условие истинно, использовать моржовый оператор можно и в нём:
Код выше будет запрашивать ввод пользователя до тех пор, пока он не введёт число.
Использовать моржовый оператор в других частях кода я считаю нецелесообразным, всегда можно создать иную, более простую альтернативу, а вот для условий и цикла while - это очень удобная конструкция.
4. Оператор else в циклах for и while
Раз уж мы затронули тему циклов, хочется несколько слов сказать о ветвлении в нём.
Думаю, всем известно, что инструкция break прерывает цикл, но как узнать, была ли она вызвана в процессе выполнения кода? В python решили, что такая проверка будет полезным дополнением и в циклах for и while добавили опциональную ветку else.
Код в этом блоке выполнится только в том случае, если оператор break не был вызван, то есть мы прошли цикл до конца или условие цикла (в случае с while) приняло значение False.
Подобную логику можно использовать при проверке какого-то объёма данных. Например, нам нужно фаззить сайт до тех пор, пока не найдётся страница с личным кабинетом, но, если такой страницы не оказалось в нашем списке, покажем соответствующее сообщение:
Если не пользоваться блоком else, придётся после цикла добавлять ещё одно условие, которое проверит последний полученный статус код.
Расскажите в комментариях, как бы вы реализовали подобную логику.
В следующих частях хочется рассказать о тонкостях работы со встроенными и пользовательскими функциями, исключениями и многом другом!
А ещё больше знаний о языке python, его использовании в вебе, фаззинге и информационной безопасности в целом вы можете получить на наших курсах в Академии Кодебай! Ну а попрактиковаться всегда можно на платформе Codeby.Games
Спасибо всем, кто дочитал! Комментарии и замечания приветствуются!
Меня зовут Дмитрий и я являюсь инструктором и соавтором курсов Основы Python и Python для Пентестера академии Codeby.
Это вторая часть серии статей, где я рассказываю о распространённых ошибках учеников курса и показываю способы исправлениях таких ситуаций. Часть 1.
1. Длинный if
Как многие из вас знают, оператор if в python используется для проверки условий. У этого оператора существуют блоки ветвления elif и else (хотя может использоваться и без них). Зачастую, когда в программах требуются сразу все элементы этой конструкции, код условия может выглядеть довольно объёмно.
Предположим, нам нужно написать небольшую программу, которая будет запрашивать у пользователя название столицы и возвращать континент, на котором расположен этот город.
Попробуем реализовать решение “в лоб”: создаём кортеж, где в каждой строке перечислим названия столиц, соответствующих континентов. Запрашиваем ввод пользователя, приводя строку к нужному регистру, и условием if проверяем по очереди все строки кортежа:
Python:
capitals = ('Каир Претория Абуджа', 'Пекин Токио Сеул', 'Москва Минск Ереван',
'Оттава Мехико Вашингтон', 'Богота Бразилиа Буэнос-Айрес',
'Канберра Веллингтон Порт-Морсби')
user_input = input('Введите название столицы: ').title()
if user_input in capitals[0]:
print(f'{user_input} находится на континенте Африка')
elif user_input in capitals[1]:
print(f'{user_input} находится на континенте Азия')
elif user_input in capitals[2]:
print(f'{user_input} находится на континенте Европа')
elif user_input in capitals[3]:
print(f'{user_input} находится на континенте Северная Америка')
elif user_input in capitals[4]:
print(f'{user_input} находится на континенте Южная Америка')
elif user_input in capitals[5]:
print(f'{user_input} находится на континенте Австралия')
else:
print(f"Данные по {user_input} не найдены!")
Но существует несколько рекомендаций по оптимизации и упрощению кода.
Первое, что я рекомендую - это поместить проверку негативного варианта в самое начало условия. Тем самым мы сразу показываем, какой ситуации хотим избежать.
Описать эту проверку можно разными способами и, думаю, многие сразу захотят использовать цикл, но я бы предложил вариант проще: проверим длину, чтобы избежать ошибки пустой строки, и “склеим” кортеж в одну строку, а через оператор in проверим вхождение:
Вторым действием я призываю активнее использовать вложенность условий. То есть расположить проверки на своих уровнях вложенности.
В нашем примере есть две проверки: первая - для проверки наличия строки в кортеже, вторая - для проверки совпадения. В таком случае разумно будет создать как раз два уровня вложенности:
Python:
if len(user_input) < 2 or user_input not in ' '.join(capitals):
print(f"Данные по {user_input=} не найдены!")
else:
if user_input in capitals[0]:
print(f'{user_input} находится на континенте Африка')
elif user_input in capitals[1]:
print(f'{user_input} находится на континенте Азия')
elif user_input in capitals[2]:
print(f'{user_input} находится на континенте Европа')
elif user_input in capitals[3]:
print(f'{user_input} находится на континенте Северная Америка')
elif user_input in capitals[4]:
print(f'{user_input} находится на континенте Южная Америка')
elif user_input in capitals[5]:
print(f'{user_input} находится на континенте Австралия')
Можно пойти ещё дальше и не описывать последнее условие, отправив его в else
Python:
if len(user_input) < 2 or user_input not in ' '.join(capitals):
print(f"Данные по {user_input=} не найдены!")
else:
if user_input in capitals[0]:
print(f'{user_input} находится на континенте Африка')
elif user_input in capitals[1]:
print(f'{user_input} находится на континенте Азия')
elif user_input in capitals[2]:
print(f'{user_input} находится на континенте Европа')
elif user_input in capitals[3]:
print(f'{user_input} находится на континенте Северная Америка')
elif user_input in capitals[4]:
print(f'{user_input} находится на континенте Южная Америка')
else:
print(f'{user_input} находится на континенте Австралия')
2. Использование словаря и if
Довольно часто использование длинного условия можно заменить словарём и условием проверки вхождения. Представьте, что нам нужно получить коды ответов сайтов и для каждого блока кодов создать определённое цветовое оформление.
Первое что приходит в голову, это создать цикл и условие:
Python:
import requests
from colorama import Fore
target_urls = ('https://codeby.net', 'https://codeby.school/', 'https://codeby.games/',
'https://codeby.games/pages/notifications', 'https://yandex.ru')
for url in target_urls:
response = requests.get(url, allow_redirects=False).status_code
if response // 100 == 2:
print(Fore.GREEN, end='')
elif response // 100 == 3:
print(Fore.CYAN, end='')
elif response // 100 == 4:
print(Fore.RED, end='')
else:
print(Fore.YELLOW, end='')
print(f'{response}{Fore.RESET} ==> {url}')
В подобной ситуации разумнее будет создать новый объект - словарь, поместив в ключи те самые коды:
Python:
codes_colors = {200: Fore.GREEN, 300: Fore.CYAN, 404: Fore.RED}
Python:
import requests
from colorama import Fore
target_urls = ('<https://codeby.net>', '<https://codeby.school/>', '<https://codeby.games/>', '<https://codeby.games/pages/notifications>', '<https://yandex.ru>')
codes_colors = {200: Fore.GREEN, 300: Fore.CYAN, 404: Fore.RED}
for url in target_urls:
response = requests.get(url, allow_redirects=False).status_code
if response not in codes_colors.keys():
print(Fore.YELLOW, end='')
else:
print(codes_colors[response], end='')
print(f'{response}{Fore.RESET} ==> {url}')
Опять же воспользуемся рекомендацией выше по расположению негативного условия в самом начале. Можно поступить ещё проще, указав не полный код, а только первую цифру в ключах, но тогда придётся получать эту цифру через деление или приведение к строке.
Как видите, подобных подход с использованием словаря в ряде случаев, делает код значительно проще и понятнее.
В версии python 3.10 была
Ссылка скрыта от гостей
конструкция switch/case, которая так же будет выполнять аналогичную задачу.3. Моржовый оператор.
Заканчивая тему условий, нельзя не сказать про введённый в версии 3.8 моржовый оператор.
Конструкция := (похожая на глаза и клыки моржа) позволяет прямо в условии if создать переменную и там же проверить её.
То есть вместо
Обратите внимание, что выражение с моржом нужно оборачивать скобками, если в следующих частях условия мы хотим продолжать работать с ним. Иначе могут возникнуть досадные ошибки логики:
Из-за того, что мы явно не указали, какой именно объект хотим получить в переменную, python стал выполнять выражение как обычно справа налево: запросил строку у пользователя и сравнил её со строкой 'password':
Python:
input('Введите пароль: ') != 'password'
В итоге, если пароль будет правильным, в переменной окажется True, иначе - False.
Если же мы хотим получить не булево значение, а введённую строку, убираем в скобки выражение с моржом
Ну а так как цикл while - это такое же условие if, только выполняющееся до тех пор, пока условие истинно, использовать моржовый оператор можно и в нём:
Код выше будет запрашивать ввод пользователя до тех пор, пока он не введёт число.
Использовать моржовый оператор в других частях кода я считаю нецелесообразным, всегда можно создать иную, более простую альтернативу, а вот для условий и цикла while - это очень удобная конструкция.
4. Оператор else в циклах for и while
Раз уж мы затронули тему циклов, хочется несколько слов сказать о ветвлении в нём.
Думаю, всем известно, что инструкция break прерывает цикл, но как узнать, была ли она вызвана в процессе выполнения кода? В python решили, что такая проверка будет полезным дополнением и в циклах for и while добавили опциональную ветку else.
Код в этом блоке выполнится только в том случае, если оператор break не был вызван, то есть мы прошли цикл до конца или условие цикла (в случае с while) приняло значение False.
Подобную логику можно использовать при проверке какого-то объёма данных. Например, нам нужно фаззить сайт до тех пор, пока не найдётся страница с личным кабинетом, но, если такой страницы не оказалось в нашем списке, покажем соответствующее сообщение:
Python:
import requests
target_dirs = 'cab cabinet kabinet admin administrator login'
url = 'https://google.com/'
for dir in target_dirs.split():
if (st_code := requests.get(f'{url}{dir}', allow_redirects=False).status_code) == 200:
print(f'Страница кабинета найдена! => {url}{dir}')
break
print(f'{url}{dir} => {st_code}')
else:
print('Поиск завершён. Страницу кабинета не нашли.')
Расскажите в комментариях, как бы вы реализовали подобную логику.
В следующих частях хочется рассказать о тонкостях работы со встроенными и пользовательскими функциями, исключениями и многом другом!
А ещё больше знаний о языке python, его использовании в вебе, фаззинге и информационной безопасности в целом вы можете получить на наших курсах в Академии Кодебай! Ну а попрактиковаться всегда можно на платформе Codeby.Games
Спасибо всем, кто дочитал! Комментарии и замечания приветствуются!