• Курсы Академии Кодебай, стартующие в мае - июне, от команды The Codeby

    1. Цифровая криминалистика и реагирование на инциденты
    2. ОС Linux (DFIR) Старт: 16 мая
    3. Анализ фишинговых атак Старт: 16 мая Устройства для тестирования на проникновение Старт: 16 мая

    Скидки до 10%

    Полный список ближайших курсов ...

Статья Наставления изучающим Python. Часть 1.

Друзья, всех приветствую!
Меня зовут Дмитрий и я являюсь инструктором и соавтором курсов Основы Python и Python для Пентестера академии Codeby.

1704498167120.png 1704498176151.png


Проверяя домашние задания слушателей, раз от раза я замечаю одни и те же недочёты и ошибки оформления. В этой серии статей мне хочется привести примеры таких ошибок и объяснить, почему тот или иной случай является ошибочным и, конечно, же показать правильные варианты.

1. Именование переменных

1704490084208.png
Первое чему учатся наши слушатели – это умению создавать и, главное, именовать переменные. В своих комментариях при проверке ДЗ я пытаюсь донести простую истину: имена переменных позволяют в первую очередь вам лучше и быстрее ориентироваться в коде программы и придумываете вы их для себя.

Поверьте мне на слово, однобуквенные имена переменных, такие как a, b или x мало что смогут сказать о содержимом этого объекта. Конечно, когда код программы небольшой и помещается на одном экране, можно быстро найти строку инициализации этой переменной и легко понять какой объект в ней находится. Но, когда подобных переменных будет 3, 5, 10, а листинг не будет помещаться на одном экране, запомнить содержимое всех переменных попросту не получится – отсюда и рождаются досадные баги и ошибки.

Внимание человека может одновременно охватывать не так уж много объектов, кому интересно, почитайте про . Поэтому не растрачивайте ваше внимание попусту, оставляйте его для запоминания логики программы.

Используйте понятные английские слова и их сокращения. Такие слова как answer, result, output дадут больше представления о том, что находится в переменной нежели однобуквенные a, b, c.
Если же слов нужно несколько, отделяйте их друг от друга нижним подчёркиванием: target_url, lines_counter, input_string. Подобный способ записи (совместно с нижним регистром всех букв) называется , в Python принято использовать её для именования локальных переменных, функций, а так же методов классов.

Следование этому правилу поможет вам быстрее ориентироваться в написанном коде, а расширение функционала программы и поиск ошибок будет проще и эффективнее. Не стоит и злоупотреблять этим правилом – создавать имена больше 3-4 слов, использовать артикли и предлоги в именах переменных так же считается плохой практикой.

Аналогично обстоит дело и с именами функций/методов. Сразу стоит обратить внимание на тот факт, что функция/метод является объектом, который что что-то делает, выполняет. В русском языке действие описывается глаголом, значит, и в имени функции нужно использовать хотя бы один глагол или причастие. Если функция что-то печатает, пусть она называется printing_output или show_result. Если же в результате вызова этой функции мы получаем какой-то объект, переменной стоит присвоить имя get_data или receive_result. Такое именование даст общее представление о результате, который мы получим после вызова функции и далее в коде мы легко отличим этот объект от локальной переменной, основываясь только на его имени.

Отдельно хочется напомнить, что использовать для именования переменных иные языке кроме английского крайне не рекомендуется!
Представьте, что в какой-то момент вам отправят на доработку подобные творения:
1704495285784.png
1704495441661.png
И ведь код этих примеров будет запускаться и даже делать то, что нужно, но вот для их понимания придётся изучать не только python, но и армянский, и грузинский языки соответственно :)

2. Аргументы функции print


Второй часто встречающийся недочёт у новичков – не эффективное использование функции .
Регулярно слушатели в вызове этой функции пытаются выполнить различные операции, в том числе и конкатенацию строк и отправляют похожие решения:
1704491856375.png
Мало того, подобный код выглядит довольно сложно, так ещё и может превышать длину строки кода в Python.
Наиболее предпочтимым является вариант использования f-строки:
1704491897667.png
в листинге выше переменная int_res сначала будет приведена к строке и после обе распечатаны.
Но самым простым способом вывести разные типы данных в функции print будет банальное перечисление их через запятую:
1704491926191.png
Таким образом функция print сама выполнит нужное приведение типов, чтобы корректно отобразить содержимое переменных

2.1. Многострочный print


Следующая ситуация, вызывающая сложность - это многострочный print.
При необходимости вывести несколько строк на печать, ученики пытаются уместить их в один вызов функции print. Да, с одной стороны это может показаться самым простым способом - мы вызываем один раз вызываем функцию, передавая ей указанные строки, но подобный листинг читается очень и очень плохо. Смотрите сами:
1704492072663.png

В случае возникновения такой задачи, можно изменить оформление разными способами:

Вариант 1. Использовать дополнительный аргумент функции print – sep. По умолчанию sep – separator – разделитель подставляет пробел вместо запятой между аргументами функции print.Мы же можем его переопредели
1704496467772.png
Мы смогли не только избавиться от лишней конкатенации, но сделали код аккуратнее.
Вариант 2. Иной подход заключается в создании переменной, с использованием тройных кавычек, в этом случае всё форматирование внутри строки будет сохранено и вывод будет точно таким же, как и представление в переменной:
1704492229197.png
Как видите, нам не понадобилось использовать дополнительные спецсимволы переноса, а код стал значительно проще.

Для вывода нескольких строк можно каждую убрать в список или кортеж, тогда и печать подобного объекта немного изменится:
1704496536136.png
В этом примере мы уже используем распаковку аргументов функции print через символ звёздочки, то есть в функцию передаётся не сам кортеж, а его содержимое – строки. Чтобы отделить аргументы друг от друга, мы вместо пробела, используемого по умолчанию, используем перенос.


Как видите, язык Python позволяет решить одну и ту же задачу сразу несколькими способами.
А вот знать эти способы, уметь их применять по месту мы как раз и учим наших слушателей!
Я приглашаю всех интересующихся языком программирования Python, компьютерными технологиями и информационной безопасностью на курсы Академии Кодебай!

В следующих частях я попытаюсь рассказать о примерах использования условий, заменой словарём нескольких условий, продвинутой работе с циклами и многом другом!


Спасибо всем, кто дочитал! Комментарии и замечания приветствуются! :)
 

abstract abstract

Green Team
12.07.2023
13
1
BIT
153
Дополню слегка. Наименование переменных уместно краткое, если в свою очередь эти переменные содержаться в небольшой области видимости. В питоне, например, уместно называть переменные в циклах как i, j, k, _ и т.д.

Что касается именования на русском/грузинском/китайском, то я бывший одинэсник, у нас наоборот ситуация :p

Вообще, за свою практику разработчика, самую популярную ошибку люди допускают всё же не в наименовании переменных, а в том, что большинство не умеет пользоваться отладчиком и всю свою карьеру используют принты :)
 

Exited3n

Red Team
10.05.2022
679
217
BIT
430
Дополню слегка. Наименование переменных уместно краткое, если в свою очередь эти переменные содержаться в небольшой области видимости. В питоне, например, уместно называть переменные в циклах как i, j, k, _ и т.д.

Что касается именования на русском/грузинском/китайском, то я бывший одинэсник, у нас наоборот ситуация :p

Вообще, за свою практику разработчика, самую популярную ошибку люди допускают всё же не в наименовании переменных, а в том, что большинство не умеет пользоваться отладчиком и всю свою карьеру используют принты :)
Принты не нужны, есть - GitHub - gruns/icecream: 🍦 Never use print() to debug again.
Вдруг кто не знает
 
  • Нравится
Реакции: aka 0vern0t, ALT1RE и f22

f22

Codeby Academy
Gold Team
05.05.2019
1 837
225
BIT
992
В питоне, например, уместно называть переменные в циклах как i, j, k, _ и т.д.
Про циклы хотел рассказать в следующих частях, но, раз уж зашла речь, то дополню: даже в циклах призываю слушателей создавать понятные имена переменных. Сравните сами:
Есть список url, которые нужно перебрать в цикле и получить содержимое страниц
Python:
urls = ('google.com', 'ya.ru', 'mail.ru')
Вот два варианта именования переменных:
Python:
for num, url in enumerate(urls, 1):
    print(f'{num}: {url}')
    
for i, j in enumerate(urls, 1):
    print(f'{i}: {j}')
Согласитесь, что в первом случае код гораздо понятнее нежели во втором.
А если мы будем перебирать не кортеж, а словарь, у которого будет 2 объекта - ключ и значение?
А если в значениях тоже будет кортеж? Нам так и алфавита может не хватить )


Отдельно про символ подчёркивания: каждый раз рекомендую использовать его в тех случаях, когда переменную объявить нужно, но использовать в теле цикла её не будем.
Например, есть кортеж списков или словарь со значениями из аналогичных наборов данных, а нужно вычленить только первый элемент или второй, так вот, чтобы не использовать индексы, можно объявить переменные сразу в условии цикла и те, что нам не пригодятся лучше использовать как раз подчёркивание.
 
  • Нравится
Реакции: Rev0x1337 и ALT1RE

abstract abstract

Green Team
12.07.2023
13
1
BIT
153
Хорошо, коллега, в вашем примере я соглашусь что в данном случае переменные имеет место быть так называть. Но, чтобы не быть голословным приведу ещё и собственный

Данный код выводит пирамиду Эйлера. Общепринятым комьюнити стандартом принято называть переменные i, j, k и т.д. в зависимости от вложенности цикла.
Python:
def euler_pyramid(n):
     pyramid = []
     for i in range(1, n+1):
         row = []
         for j in range(1, i+1):
             row.append(j)
         for j in reversed(range(1, i)):
             row.append(j)
         pyramid.append(row)
     return pyramid

Гораздо хуже выглядел бы следующий код
Python:
def euler_pyramid(n):
     pyramid = []
     for num1 in range(1, n+1):
         row = []
         for num2 in range(1, num1+1):
             row.append(num2)
         for num2 in reversed(range(1, num1)):
             row.append(num2)
         pyramid.append(row)
     return pyramid

Так же в вашем коде не обязательно было переименовывать num в i и он бы выглядел бы следующим образом, тоже понятно для другого программиста. Даже больше скажу, переменная num вызывает неоднозначность и не отвечает за индексакцию в циклах.
Python:
for i, url in enumerate(urls, 1):
    print(f'{i}: {url}')
 

f22

Codeby Academy
Gold Team
05.05.2019
1 837
225
BIT
992
Спасибо за пример!

Я соглашусь, что для ряда задач будет разумнее использовать более короткую запись переменных
Но поймите меня правильно: на наших курсах обучаются слушатели, у которых совсем мало опыта программирования и им в первую очередь нужно набить руку, писать как можно больше кода, понимать принципы работы циклов.

Именно поэтому я бы старался добиться от них введения понятных имён независимо от
Общепринятым комьюнити стандартом
Да и code style в коммерческих компаниях всегда будет приоритетнее, чем такого рода стандарт.


Гораздо хуже выглядел бы следующий код
И тут соглашусь, что код будет сложно читаемым, но и его можно доработать)
Я бы предложил вариант с созданием ещё одной функции. Да, дополнительный вызов скажется на производительности, но мы же говорим об обучении
Python:
def make_row(cur_num):
    left_part = [elem for elem in range(1, cur_num+1)]
 
    return left_part + left_part[::-1][1:]


def euler_pyramid(n):
     pyramid = []
     for i in range(1, n+1):
         row = make_row(i)
         pyramid.append(row)
       
     return pyramid


result = euler_pyramid(20)

for line in result:
    print(' '.join(map(str, line)))

Думаю, что конструкцию
Python:
row = []
for num2 in range(1, num1+1):
    row.append(num2)
for num2 in reversed(range(1, num1)):
    row.append(num2)
pyramid.append(row)
гораздо сложнее понять, нежели
Python:
row = make_row(i)
pyramid.append(row)


переменная num вызывает неоднозначность и не отвечает за индексакцию в циклах.
Довольно спорное утверждение.
 

abstract abstract

Green Team
12.07.2023
13
1
BIT
153
Новичок != глупый человек. Это человек, который как губка впитывает знания и совершает множество ошибок, которые потом их же и закрепляет. Причём данный опыт его будет преследовать до тех пор, пока он не встретит противоположное мнение, которое может, но не обязательно его переубедит (в большинстве случаев не переубеждает). Прочитав вашу статью, тот же самый новичок, будет думать что переменные НЕ должны быть односимвольными, кто-то даже скинет ссылку на вашу статью, утверждая что "а я на форуме codeby вычитал что это так должно быть".

Мозг устроен таким образом, что встречая что-то категорично-утвердительное мы даже не задумываемся о том, что это нечто категорично-утвердительное не является истиной в последней инстанции.

На счёт общепринятых стандартов в компаниях и стандартам в сообществе... Я не встречал ни одну фирму которая намерено не следовала стандартам pep8. Наоборот, я даже сталкивался с библиотеками в этих же самых фирмах, которые заставляют программистов следовать ему. Так что фирма, которая пишет код не следуя общепринятым стандартам в комьюнити является скорее исключением, нежели чем правилом. Плюс, после работы в подобной компании где существуют свои регламенты по оформлению кода достаточно сложно переучиваться даже профессионалам.
 

yetiraki

Cybercoliseum II
07.02.2023
50
78
BIT
191
Ну и я вставлю свои 5 копеек. Сам был джунгм пару раз. Потом частенько с джунами уже беседовал.

По моему опыту проблема на в глупости ддунов, а в несовершенстве материалов обучения. Везде я видел как раз бездумное определение переменных a, b, c, x1, x2 и т.п.
А джун что - видит в материалах, запоминает и применяет. Необходимо подавать материал сразу с нормальным определением переменных и тогда у джуна нормой станет нормальное определение.

А i,j,k и n, m - это уже классика, которая наврядли уйдет из обихода.
 
  • Нравится
Реакции: aka 0vern0t, Dzen и f22

unickname3

One Level
06.12.2023
6
3
BIT
125
Данный код выводит пирамиду Эйлера. Общепринятым комьюнити стандартом принято называть переменные i, j, k и т.д. в зависимости от вложенности цикла.
Python:
def euler_pyramid(n):
     pyramid = []
     for i in range(1, n+1):
         row = []
         for j in range(1, i+1):
             row.append(j)
         for j in reversed(range(1, i)):
             row.append(j)
         pyramid.append(row)
     return pyramid
Существенная доля таких случаев же схлопывается списковыми генераторами и прочим сахаром или методами стандартной библиотеки. Например:

Python:
def create_euler_pyramid(pyramid_height):
    pyramid = []
    for i in range(1, pyramid_height + 1):
        row = list(range(1, i + 1)) + list(range(i - 1, 0, -1))
        pyramid.append(row)
    return pyramid

Да, однобуквенные названия переменных i,j,k принято использовать не для переменных вообще, а конкретно для индексов.

Недавно разбирал папку со своими решения проекта Эйлера пятилетней, примерно, давности. И очень ругался на того, кто писал код - он то понимал, за что какая буковка в реализуемом алгоритме отвечает, а я сейчас, глядя на код с большим трудом понимаю, как вообще этот хитрый алгоритм работает. Согласен, что не так просто придумать название для переменных в абстрактных математических алгоритмах, но сэкономленые пять минут тогда выросли в 15-20, а то и более, сейчас.
 
  • Нравится
Реакции: f22

abstract abstract

Green Team
12.07.2023
13
1
BIT
153
Ещё одним плюсом однобуквенных переменных в циклах в том, что ты можешь понять на каком уровне вложенности циклов ты находишься

Вообще, решения через синтаксических сахар конечно хоть и приятно делать, да и много кто так делает, но, к сожалению, код от этого не становится понятным. Код в большинстве мы читаем, поэтому, я бы в той программе, которую потом люди дорабатывают, всё же пытался соблюсти чистоту (исключения - обфускация)
 

Checat

One Level
01.04.2024
1
1
BIT
29
Всем здравствуйте. Выскажу свое мнение со стороны человека, который 2 месяца как начал изучать python, а накануне писал на старом и добром delphi.
Перед прохождением курса "Пайтон для новичков" (здесь, на codeby), читал Эрика Мэтиза "Изучаем Python" и немного решал задачи из задачника Бена Стивенсона, а также учился по одному из курсов udemy. Так вот, везде говорилось про PEP8 и читаемость кода, но вскользь. В итоге, до "Пайтон для новичков" в моих примерах легко можно было найти буквенные переменные. И именно f22 в учебных материалах курса, акцентировал внимание на имена переменных, да и в целом на PEP8. Поэтому сейчас, я прекрасно понимаю, что можно назвать переменную одной буквой, но каждый раз выбираю наименование осмысленно. В итоге из кода исчезли однобуквенные имена сами по себе, и код прибавил в качестве оформления.
 
  • Нравится
Реакции: f22
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!