progway — программирование, IT
2.73K subscribers
25 photos
1 video
246 links
Чат: @prog_way_chat

Разборы вопросов и задач с собеседований, мысли, полезные материалы и просто вещи, что мне интересны из мира IT

Полезности и навигация в закрепе

По всем вопросам: @denisputnov
Download Telegram
Аннотации в Python.

Типизация переменных в языках - это вечная тема для обсуждения. Кому-то нравится, статическая типизация, как в Dart, например, когда мы явно объявляем новые переменные и указываем какие типы данных они могут в себе содержать, в то время, как другим нравится динамическая типизация, как в Python, где в любой момент времени можно создать и использовать новую переменную любого типа. Сейчас не будем обсуждать что лучше, а что хуже, а поговорим о том как указать тип переменной в Python явно.

Указание типа переменной происходит по определенному синтаксису, который лучше показать, чем объяснить:

def say_hello(name: str, age: int) -> None:
print(f"Hello, {name}. I know, you're {age} years old.")


Вот такая замечательная функция у нас появилось. Мы явно указываем, что name - это строка, age - целое число, а сама функция должна возвращать None, и теперь большинство сред разработки будут указывать нам типы переменных, когда мы захотим использовать эту функцию, НО это лишь визуальное указание, никаких изменений в ход программы это не внесёт. О чём речь? Попробуем выполнить эту функцию:

say_hello('Денис', 19)
>>> Hello, Денис. I know, you're 19 years old.

# всё бы хорошо, но попробуем так:

say_hello([1, 2, 3], "СТРОКА")
>>> Hello, [1, 2, 3]. I know, you're СТРОКА years old.


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

def say_hello(name: str, age: int) -> None:
if isinstance(name, str) and isinstance(age, int):
print(f"Hello, {name}. I know, you're {age} years old.")
else:
raise TypeError('Подан неверный тип переменной')

say_hello('Денис', 19)
>>> Hello, Денис. I know, you're 19 years old.

say_hello([1, 2, 3], "СТРОКА")
>>> TypeError: Подан неверный тип переменной


Теперь наша программа прервётся, если мы подадим в функцию неправильные входные параметры. Ну и, опять же, тема очень обширная, советую ознакомиться подробнее. Спасибо, что читаете ❤️

#python
Сегодня совсем коротко, но зато со смыслом.

Думаю, многие знают, что в Python есть такие операторы, как is и ==. Оба они идейно похожи - они указывают на равенство объектов. Казалось бы, одно и то же, но давайте на примере:

#  объявим наши переменные
# таким образом
a = [1, 2, 3]

b = a

c = [1, 2, 3]


Отлично, проверим?

a == b
>>> True
a is b
>>> True
a == c
>>> True
a is c
>>> False


Первые три выражения дали вполне ожидаемый ответ, а с последним всё не так однозначно.
a == b == c == [1, 2, 3] , с этим не поспорить. b = a, значит b - ссылка на объект a, следовательно обе переменные ссылаются на один и тот же список [1, 2, 3] в памяти. А вот c - это уже новый объект в памяти, и пусть даже c == a, но это разные объекты. Именно поэтому a is c ⇒ False.

В этом и заключается вся разница.

#python
Области видимости в Python.

Так, с последним моим переездом пропустил два дня для поста, но, собственно, ничего вроде страшного. Сейчас я снова в стою и буду писать, пока пишется.

Области видимости (О.В. в примере) в языках программирования рассматриваются как некоторые сущности, знаете. Этот термин подразумевает область программы, откуда будет доступна переменная, функция и т.п. структуры.

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

#  глобальная O.B.

a = 5
b = 6

def foo(): # foo О.В.
c = 7
return a * b

foo()
>>> 30
print(c)
>>> NameError: name 'c' is not defined


Что тут происходит? Всё просто: две переменные a и b мы объявляем в глобальной области видимости, а c в области видимости функции foo. И тут нужно понять, что области видимости работают по принципу вложенности: переменные из родителя доступны в ребёнке, но не наоборот (!).

Таким образом переменные a и b доступны в функции foo, но c не доступна в глобальной области видимости, переменная локальна.

Кстати, с областями видимости есть классная и очень интересная особенность - замкнутость. Она много где используется, например в тех-же декораторах. Может быть я напишу об этом позже, конечно, но советую самостоятельно ознакомиться, тема интересная. Ну и конечно же есть смысл посмотреть про ключевые слова global и nonlocal, но помните, что использование этих ключевых слов не очень хороший тон в программировании.

Спасибо прочтение и классный фидбек в личных сообщениях, это дорогого стоит

#python
Зачем нужны абстрактные методы и классы?

Думаю, что многие знаю о существовании абстракции в языках программирования, но даже если вы не слышали об этом, то сейчас я объясню это в максимально простом виде 🙃

Давайте начну с примера из личного опыта. Может быть затяну из-за этого, но должно быть интересно. Так вот, недавно я работал в стартапе из кремниевой долины. Мы с командой создавали чат-бота, который будет работать во всех мессенджерах, будь то Telegram, VK, What's App, Viber или Facebook Messenger.

Как тут быть? У каждого мессенджера свой API со своими входными и выходными, мы столкнулись с проблемой стандартизации. Тогда мы просто взяли и написали свой интерфейс для каждого мессенджера. Стандартом интерфейса и стал абстрактный класс с абстрактными методами. Так что же это такое?

Абстрактный класс - класс, унаследованный от класса ABC и содержащий абстрактные методы.
Абстрактный метод - метод класса, задекорированный декоратором @abstractmethod и не имеющей реализации. Такой метод нужен только для объявления.

Давайте на примере, так будет яснее. Отдалённо повторим интерфейс мессенджера из нашего проекта:

from abc import ABC, abstractmethod

class Interface(ABC):

@abstractmethod
def send_message(self, chat_id, *args, **kwargs):
pass

@abstractmethod
def send_photo(self, chat_id, txt=None, *args, **kvargs):
pass

@abstractmethod
def send_file(self, file, txt=None, media=None):
pass

# Ну и так далее


Что происходит в этом примере? Я объявил класс Interface, который унаследован от абстрактного класса ABC. В этом классе я объявил 3 абстрактных метода. У них нет реализации. Суть абстрактного класса заключается лишь в том, чтобы обязать наследника класса Interface реализовать все необходимые методы.

Потом мы реализуем класс, например Telegram, где реализуем метод send_message одним кодом, а в классе WhatsApp реализуем тот же метод совсем по другому. Нас не волнует как это работает внутри, мы лишь описываем необходимый интерфейс взаимодействия.

Надеюсь этот пример помог вам понять что это такое и немного разобраться.

#python
Зачем нужен json.

Казалось бы, вопрос вполне очевидный, но далеко не для всех. Сегодня расскажу про json и его особенности.

Итак, json - это формат передачи данных. Многие связывают его исключительно с JavaScript и WebDev, но в современном мире это далеко не так. Многие языки способны обрабатывать json и имеют для этого встроенные функции/модули. Например в Python есть встроенный пакет json, который позволит вам легко обработать этот формат и, например, перевести json в обычный питоновский словарь для облегчения работы.

Что же делает json таким популярным? Ну, очевидно, это удобство использования. Если вспоминать ближайшего конкурента, а именно xml, то лично мне json кажется более читабельным и удобным в работе. В своей практике я работал с обоими технологиями, и правды ради обе удобны. У каждой есть свои плюсы и минусы, но и сферы применения так же разнятся.

Но насчёт читабельности, предлагаю оформить одну и ту же структуру данных сначала в json, а затем в xml:

{
"name": "JavaScript для чайников",
"authors": [
"Крис Минник",
"Ева Холланд"
],
"publisher": {
"name": "Диалектика",
"email": "info@dialektika.com",
"site": "www.dialektika.com"
}
}

Вот такая произвольная структура получилась для книги, которую я читаю в данный момент, кстати. Теперь повторим ее на xml:

<book>
<name>JavaScript для чайников</name>
<authors>
<author>Крис Минник</author>
<author>Ева Холланд</author>
</authors>
<publisher>
<name>Диалектика</name>
<email>info@dialektika.com</email>
<site>www.dialektika.com</site>
</publisher>
</book>

Не знаю как вам, но лично мне json кажется в разы дружелюбнее и читабельнее.

Используется же json чаще всего в случаях, когда нужно быстро получить какой-то ответ от сервера. И речь тут не только о Web. Например, в формате json ответ от сервера могут получать мобильные приложения. Ну и конечно же этот формат данных крайне популярен в REST API, о которых я писал тут.

#python #web #mobile
Ещё один оператор присвоения в Python.

Думаю мало кто знает (ведь для многих людей читать спеки - грех), но в python 3.8+ появился новый оператор присвоения - Walrus operator. Я точно не знаю как перевести его на русский, но Google Translate говорит, что это "Моржовой оператор", так что не будем перечить гуру. В чём суть?

Теперь в Python есть два оператора присваивания:
# обычное присваивание
# 1. Присваивает переменной x значение 5
x = 5

# walrus operator
# 1. Присваивает переменной x значение 5
# 2. Возвращает 5
(x := 5)

Понятнее на примере:
1. Обычное присваивание:
with open(file) as f:
while True:
chunk = f.read(8192)
if not chunk:
break
chunk_processing(chunk)

2. Walrus operator:
with open(file) as f:
while chink := f.read(8192):
chunk_processing(chunk)

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

#python
Запускаем своего первого телеграм бота на Python.

Я уже как-то затрагивал ботов обзорно вот в этом посте, сегодня хочу продолжить немного более конкретно. Итак, телеграм сейчас является самой лучшей площадкой для создания ботов. Ни один другой мессенджер или соцсеть не может похвастаться таким же успехом в этом деле. Объяснить это просто:

1. У телеграма прекрасный, удобный, хорошо задокументированный API.
2. Для него уже сейчас существует огромная кодовая база, десятки библиотек на самых разных языках программирования.

Для примера я взял Python, так как этот язык наиболее распространен среди аудитории моего канала, как мне кажется. Для Python есть две неплохие библиотеки - это pyTelegramBotApi и aiogram. Я написал уже где-то ботов 15 за всё время программирования и с уверенностью могу сказать, что на моей практике это лучшие библиотеки.

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

Для начала зарегистрируем нового бота у @botfather. Это не сложно, не будем на этом останавливаться.

Потом установим библиотеку:
pip install pyTelegramBotApi

Далее создадим файл bot.py и напишем вот такой код:
import telebot

bot = telebot.TeleBot(токен от @BotFather)

@bot.message_handler(commands=['start'])
def send_welcome(message):
bot.send_message(message.chat.id, "привет")

bot.polling(none_stop=True)

Далее разберем основы:
Первое, что нужно обсудить - это объект message, который в себя принимает функция send_message. Message - обычный питоновский словарь, к которому мы можем обращаться по ключам. Принт этого объекта можно посмотреть тут.

Второе, конечно же, декоратор bot.message_handler(commands=['start']). Весь его функционал заключается в том, что функция, обёрнутая декоратором, будет выполнятся на определенную команду, например. То есть мы можем оформить декоратор bot.message_handler(commands=['help', 'помощь']) и описанная ниже функция сработает при командах /help и /помощь.

Это, конечно же, не единственный декоратор, который есть в библиотеке, но его одного достаточно для простейшего бота.

Насчёт bot.send_message.
Это метод, который, как очевидно, отправляет сообщение пользователю. В приведенном выше примере мы отправляем сообщение по идентификатору message.chat.id, то есть в ответ пользователю. У этого класса есть еще много методов, например для отправки фотографии, аудио, игр или других действий.

Теперь я напишу маленького бота, на примере которого, я надеюсь, вы поймёте тему лучше.

Посмотреть код можно тут.
Взаимодействовать с ботом: @progway_test_bot

И, как всегда, спасибо за прочтение ❤️

#python #chatbot
Как передать параметры в программу Python из консоли.

Я думаю многие видели конструкции запуска файлов типа
python file.py -n ProgWay —url t.me/prog_way_blog
Такие конструкции бывают полезны, когда скрипт запускается с определенными параметрами автоматически. Как самый близкий мне пример, когда нужно реализовать автоматизированный обработчик логов. Мы получаем на сервер новый чанк информации, засовываем её в в скрипт и на выходе получаем проанализированный файлик, например.

В общем, штука полезная и знать её точно стоило бы, но как реализовать - непонятно.
Я покажу 2 способа:

Первый через встроенную библиотеку sys. Мы получаем список всех аргументов, которые у нас есть при запуске, и уже после можем по нему итерироваться, например:
import sys

for param in sys.argv:
print(param)

Тогда при запуске вот такой конструкции:
python file.py -n ProgWay —url t.me/prog_way_blog
Мы получим вывод:
file.py
-n
ProgWay
—url
t.me/prog_way_blog

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

Второй вариант уже куда более изящный - там я использую библиотеку argparse:
import sys 
import argparse

def getArgs():
parser = argparse.ArgumentParser()
parser.add_argument('-n', '--name', default="ProgWay")
parser.add_argument('-u', '--url', default="t.me/prog_way_blog")
return parser.parse_args()


if __name__ == "__main__":
args = getArgs()
print(args.name)

Тогда при вводе той же строки:
python file.py -n ProgWay —url t.me/prog_way_blog
Мы получим объект, из которого по ключам можем легко достать любой аргумент.

args.name // ProgWay
args.url // t.me/prog_way_blog

Таким образом организовать получение аргументов из командной строки очень просто и эффективно. Спасибо за прочтение ❤️

#python
О сокращении операторов сравнения в Python.

По сути своей, операция сравнения в языках программирования - это бинарная операция, то есть сравнение возможно только для двух объектов. Если объект будет один, то не понятно с чем сравнивать, а если больше 2, то не понятно как. Но если нужно организовать проверку переменной на вхождение в какой-то в диапазон, то обычно это делают так:
a = 5

if (a > 1) and (a < 9):
print(a)

Но на самом деле в Python можно записать то же самое, только используя обычные правила математики:
a = 5

if 1 < a < 9:
print(a)

В JavaScript, например, при такой записи условие просто не сработает и при любом значении переменной оператор выполнится.

В Python же подобные цепочки нормально распознаются и они могут быть чуть ли не бесконечными, то есть условие
1 < a < b < c < d < e < 9
в Python считается достаточно обыденным и распознается без проблем.

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

#python
Модульность в Python.

Есть несколько видов импортов, которые вы можете использовать. Самые простые - импорты стандартных и установленных библиотек, например:
import Flask 
from random import randint

С этими импортами многие знакомы, останавливаться на них не будем.

При работе над большим проектом ваша кодовая база очень быстро разрастается. Чтобы оформить качественную декомпозицию, оформить зоны ответственности и упростить проект в целом можно разбить проект на несколько компонентов (структура проекта на приложенной картинке и на github).

Чтобы импортировать файл из той же папки, в которой находится исполняемый файл, можно использовать уже знакомую конструкцию. Допустим, рядом есть файл config.py, куда вынесены все константы. Импортировать его можно так:
import config

Также рядом с исполняемым файлом вы можете создать папку, куда вложите config.py. Такой файл можно импортировать вот так:
from folder import utils

Из вложенной в папку папки (какое странно выражение) импортируем так:
from folder.folder2 import utils2

Также вы можете создать собственный независимый проект, чтобы переиспользовать его где-то ещё. Для этого рядом с главным файлом мы создадим папку package с файлами __init__.py и functions.py.
Содержание файла __init__.py:
from package.functions import sayHello

def init():
print('Инициализировано')

Содержание файла functions.py:
def sayHello():
print('hello')

Теперь в главном файле просто импортируем наш package, с такой структурой нам будут доступны все вложенные функции.

Тема сложнее, чем можно рассмотреть в одном моём посте, так что заинтересовавшиеся погуглят ещё, надеюсь. Мой тестовый проект доступен на github. Хранит вас бог.

#python
О переменных окружения.

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

Как можно хранить секретные ключи и переменные:
1. Просто в коде.
Заранее провальный метод, все ключи просто видно.

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

3. В переменных окружения.
Это достаточно унифицированный для всех проектов и программистов способ, а это очень ценится. Очень удобно работать и вот это вот всё.

В общем, об этом много где говорят, даже я использовал это вот в этом посте, но почему-то конкретные вещи никто не раскрывает. В этом посте ответ сразу на 2 вопроса:

1. Как установить переменную окружения?
Нагуглить ответ на этот вопрос крайне просто, если вы пользуетесь UNIX системами (linux/macos и т.д.), но как мы все знает, консоль windows отвратительна. А ещё windows используют всё же большинство, так что поговорим именно о нём.

Чтобы установить переменную окружения в windows необходимо написать следующую команду в консоли:
set VARIABLE_NAME=value

Команда же set выведет в консоль все переменные окружения.

2. Как получить уже установленную переменную окружения?
Всё проще, чем кажется. За это отвечает встроенный модуль os. Получить переменную можно так:
import os 

TOKEN = os.getenv('TOKEN')

На этом всё, это действительно так просто.

Используйте переменные среды, следите за безопасностью,ну и любите и будьте любимы.

#python #useful
Что такое ifmain конструкция в Python.

Начнём с того, что конструкция выглядит так:
if __name__ == "__main__":
do_somethink()

Здесь __name__ - это "магическая" переменная, содержащая внутри себя название файла, откуда выполняется какая-то функция или операция. Допустим, что у нас есть 2 файла: main.py и file.py.
Внутри файла file.py имеем код:
def foo():
print(f"А я {__name__}")

В файле main.py реализуем такой код:
import file

print(f"Я {__name__}")
file.foo()

Тогда получим вывод:
>>> Я __main__
>>> А я file.py

Так вот, вышеописанная конструкция проверяет является ли файл главным в стеке вызовов. Все операции, реализованные внутри условия, не выполнятся, если этот файл не будет главным.

Если в файле file.py мы так же добавим:
if __name__ == "__main__":
print("Привет из условия file.py")

То данный принт мы не увидим, потому что главным файлом в цепочке является файл main.py, а переменная __name__ у файла file.py равна "file.py".

Надеюсь, что объяснил понятно. Перепишу, если будут вопросы. В будущем планирую сделать ещё более подробный пост о магических методах, так что предлагаю вам читать меня чаще :)

#python
Тернарный оператор в Python.

Есть такая полезная штука во многих языках программирования, как тернарный оператор. Чтобы понять пользу всей этой конструкции давайте рассмотрим такую задачу:
У нас есть переменная num, в которую пользователь положит число. Если num ≥ 0, то в консоль выведем "Положительное либо ноль", а иначе выведем "Отрицательное".

Реализуем код:
num = int(input())

if num >= 0:
print("Положительное либо ноль")
else:
print("Отрицательное")

С помощью тернарного оператора имплементация решения этой же задачи выглядит так:
num = int(input())

print("Положительное либо ноль" if num >= 0 else "Отрицательное")

По моему решение выглядит очень лаконично. Более удачный тут пример - функция, возвращающая модуль числа. Обычно ее записывают вот так:
def abs(num):
if num >= 0:
return num
return -num

Но с тернарным оператором она будет выглядеть вот так:
def abs(num):
return num if num >= 0 else -num

Читабельный и красивый код, советую. Кстати, пока писал решение задачи, вспомнил про унарные операторы. Когда-нибудь тоже об этом расскажу.

Спасибо за прочтение ❤️

#python
Цикл for для списков и словарей.

Я думаю многие знают стандартный способ запуска цикла for для Python через встроенную функцию range(). Записывается он вот так:
for i in range(10):
print(i)


Но на самом деле в Python существует намного больше способов итерирования. Сегодня рассмотрим некоторые из них. Для работы нам понадобятся некоторые переменные, которые можно посмотреть тут.

Чтож, предлагаю начать со списков. Для итерирования я предлагаю вам использовать оператор in. Тогда запись будет выглядеть вот так:
for value in object: 
somethink()


На конкретном примере:
for id_ in subscribersIdList:
print(id_)


Я использую переменную id_ с нижним подчёркиванием после только для того, чтобы избежать совпадения с зарезервированным именем в Python, функцией id().

Если мы будем рассматривать словари, то всё уже гораздо интереснее. Запишем такой вариант:
for key in dict:
somethink()


Тогда на примере:
for city in temperature:
print(f"In {city}: {temperature[city]}°C")


Как вы можете заметить, это очень удобно, но обращаться к словарю temperature по ключу не очень удобно. Чтобы упростить работу придётся познакомиться со встроенным методом списка items(). Он возвращает нам список кортежей формата (key, value). Подробнее смотреть сноску.

Применяя этот метод получаем типовую структуру:
for key, value in dict.items():
somethink()


На примере это будет выглядеть так:
for city, temp in temperature.items():
print(f"In {city}: {temp}°C")


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

#python
Оператор in и немного о строках.

Раз уж я в прошлом посте вспомнил о списках и словарях, то научимся использовать in не только для итерации, а для булевых функций. Кстати, прошлый пост тоже советуется к прочтению.

Так вот, в дополнение к прошлому посту скажу, что через for in можно перебирать так же и символы в строке:
for char in string:
print(char)

Как-то совсем забыл об этом, но знать точно стоит. Ну а теперь заведём переменные:
string = "Я бы любил тебя, но ты не Python"

temperature = {
"Moscow" : 11,
"New York": 12,
}
names = [
"Helen",
"Denis",
]

Отлично. С помощью оператора in мы можем проверить почти любое вхождение в объект, вашему вниманию вот такие записи:
>>> "любил тебя" in string // True
>>> "Moscow" in temperature // True
>>> "Helen" in names // True

Я считаю, что они интуитивно понятны. Но стоит обратить внимание вот на что:
>>> "denis" in names // False

В случае строк этот оператор чувствителен к регистру и ищет лишь полное соответствие. Если понадобится найти вхождение независимо, то можно привести строки, например, к нижнему регистру при помощи метода lower().

Удобно? Я думаю, что очень. Уж точно удобнее некоторых методов поиска для строк, так ещё и в разы читабельнее.

Спасибо за прочтение, это правда очень важно ❤️

#python
Встроенная функция enumerate.

Гениальная и простая и очень полезная функция. Она позволяет вам пронумеровать ваши данные. Рассмотрим на самых простых для понимания примерах, а именно на строках и списках:
string = 'progway'
names = ['Denis', 'Helen', 'Mark']

enumerate(names)
>>> <enumerate object at 0x00D624C8>

list(enumerate(string))
>>> [(0, 'p'), (1, 'r'), (2, 'o'), (3, 'g'), (4, ....]
list(enumerate(names))
>>> [(0, 'Denis'), (1, 'Helen'), (2, 'Mark')]

Как вы можете видеть, функция enumerate возвращает итерируемый объект без представления для пользователя. Поэтому мы делаем списки из этих объектов через конструктор list(). Таким образом, enumerate возвращает список пронумерованных кортежей типа (num, value).

Самый тривиальный вариант применения - цикл for:
for num, name in enumerate(names, 1):
print(f'{num}: {name}')

Как вы можете заметить, у функции enumerate я указал второй позиционный аргумент. Это число, с которого функция будет нумеровать наши данные. Изначально функция нумерует начиная с нуля, но в данном случае мы начнём с единицы.

Счастья, здоровья вам, и долгих лет жизни. А главное счастья. И здоровья. Счастья.

#python
Что такое list comprehension в Python.

Очень удобная сущность, которая позволяет определять списки. Самое приятное тут то, что с помощью list comprehension мы определим список быстрее, чем любым другим способом, если я не ошибаюсь.
Итак, вот как выглядит полная структура:
[foo(x) if condition else bar(x) for x in sequence]

Это общая формула. Блоки else и if не обязательны, то есть наше представление списков может быть упрощёно вплоть до:
[x for x in sequence]

Не знаю как объяснить это кратко и понятно, получается либо так, либо так. Так что давайте напишем несколько представлений с пояснениями. Все примеры с красивой подсветкой синтаксиса можно посмотреть тут.
/// квадраты натуральных чисел от 1 до 10
[x ** 2 for x in range(1, 11)]

/// только чётные натуральные числа от 1 до 20
[x for x in range(1, 21) if x % 2 == 0]

Обратите внимание на то, что if тут в конце. Такая запись характерна для list comprehension без блока else

/// получить список символов из строки
[letter for letter in word]

Насчёт многочисленных условий:

/// список чисел от 1 до 200, одновременно делящихся на 2, 7 и 11
[x for x in range(1, 201) if x % 2 == 0 and x % 7 == 0 and x % 11 == 0]

Кстати, такое число всего одно: 154 = 2 * 7 * 11

/// список кортежей типа (type, num) от 1 до 5
[("Нечётное", x) if x % 2 != 0 else ("Чётное", x) for x in range(1,6)]

Надеюсь эти примеры оказались наглядными и помогут вам в понимании темы. Напоминаю, что все примеры с красивой подсветкой синтаксиса можно ещё раз посмотреть тут.

Ну и конечно же спасибо за прочтение, это важно для меня ❤️

#python
Генераторы и comprehensions в Python.

Немного не так подал терминологию в предыдущем посте, на что меня справедливо поправили, спасибо.

Comprehensions ≠ генератор.
Я поспешил упростить теорию, но по хорошему путать эти сущности не нужно. В интернетах ваших часто встречается объяснение comprehensions именно как генераторов, но на самом деле генератор - это уже совершенно иная вещь, о которой я планировал рассказать чуть позже, так что в скором времени будет пост ещё и о них.

На самом деле верно определить list comprehensions как один из вариантов представления списка. Можно получить список в цикле for, например, а можно при помощи list comprehensions. Преимущество такого представления, как я и сказал, в скорости и краткости записи. Но так как эта запись, по сути, возвращает нам новый список, часто её называют генератором, что не верно.

Прошлый пост я поправил, в следующих постах постараюсь больше такого не допускать. Добра вам.

#python
Представление словарей и множеств.

Совершенно маленькое, но очень полезное дополнение к посту о list comprehensions. Аналогичным способом можно создавать списки и множества. Сразу на примере:
/// список
[x ** 2 for x in range(1, 11)]

/// множество
{x ** 2 for x in range(1, 11)}

/// словарь
{x: x**2 for x in range(1, 11)}

Полная формула для словарей выглядит сложнее:
{ (key if condition else defaultKey):(value if condition
else defaultValue) for key, value in sequence }

А вот для списков она аналогична list comprehensions.

#python
Список доступных хештегов:

Основные
:
#theory — общая теория программирования, разбор теоретических вопросов с собеседования
#quiz — короткий вопрос на свободную тему в разработке с вариантами ответов
#useful — просто полезные вещи
#blog — посты в формате блога обо мне / на свободную тему

Подгруппы:
#javascript — всё, связанное с языком
#typescript — аналогично 👆
#code — посты во встроенным в текст кодом, готовые примеры
#vite — посты, которые так или иначе затрагивают сборщик
#web — всё, касательно web разработки
#principles — принципы проектирования
#react — всё, касательно React
#patterns — всё о паттернах
#data — всё о данных и манипуляциях с ними
#news — новости

@deprecated
#python — всё, связанное с этим языком
#mobile — мобильная разработка
#design — штучки для дизайна
#github — интересности с гита
#chatbot — мои боты и всё, что с ними связано
Please open Telegram to view this post
VIEW IN TELEGRAM