CoolPython
4.68K subscribers
20 photos
44 links
Канал об основах Python и хороших практиках разработки. Создаём системность в обрывочных знаниях.

Тем, кто хочет понимать, что пишет!
Download Telegram
Магические методы

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

Давно хотела о них написать вводную и вот авторы канала @it_resume любезно подготовили для нас с вами карточки.

Наслаждайтесь!
Про культуру коммитов

Работаю над куском кода, который опирается на json файл. Файл этот длиной 7к+ строк (только не спрашивайте, как так вышло). И кусок этот одновременно
- сложный
- используется большим количеством пользователей.

И тут из мастера в этот json прилетают изменения. В которых во всем файле пробелы заменены на табы. То есть, дифф слишком большой и отсмотреть глазами не получается. Поправлю, конечно, но досадно -- и небезопасно.

В связи с чем напоминаю, как коммитить (вот, например, хорошая статья от другого автора)

Для меня главное в этом тексте:
Один коммит = одна атомарная задача

И от себя бы еще добавила:
Дифф удобно смотреть ривьюеру

Чтобы этого добиться, перед каждым коммитом нужно отсматривать изменения в каждом файле, которые хотите залить в репо: с помощью git diff или в IDE.

И еще я никогда не делаю

git add .

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

Поделитесь, какие хорошие практики работы с git вы усвоили за время работы?
​​Уже больше часа лежит весь Фейсбук. Вместе с продуктами компании (WhatsApp, Instagram, мессенджером), отвалились даже DNS и страница статусов https://status.fb.com. И может не работать всё то, что опиралось на fb.

Интересно, что случилось.
Вопрос по Python. Как думаете, является ли тип complex составным?
Anonymous Quiz
19%
Это простой тип
36%
Это составной тип
45%
Что такое complex?
Пара фактов о численных типах
(которые вы, возможно, не знали)

Факт 1

В Python есть три встроенных численных типа. Кроме int и float, которыми мы обычно пользуемся, есть еще complex — комплексные числа.

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

Сконструировать комплексное число в Python можно так:

a = complex(2, 1)

или вот так:

a = 2 + 1j

Получится одно и то же.

Факт 2

Все численные типы в Python унаследованы от класса Number. Проверить это можно так:

from numbers import Number

isinstance(1984, Number) #True
isinstance(3.1415926, Number) #True
isinstance(1j, Number) #True

Кстати, сюрприз: bool тоже унаследован от Number:

isinstance(False, Number) #True

Факт 3

Под капотом логический тип — те же числа, только bool имеет всего два значения: 0 и 1. Это обеспечивает нам легкое приведение True к единице, а False к нулю.

Это же, впрочем, дает ни разу не интуитивное поведение в некоторых случаях:

1/False # ZeroDivisionError: division by zero

True * 1 # 1
False * 1 # 0

complex(True, 3.9) # (1+3.9j)

my_list = [1, 2, 3, 4]
my_list[False] # 1

"False"[True] # a

А, и да

Факт 4

Complex не является составным типом. Это просто объект, который принимает до двух параметров при инициализации.

Такие дела!🤗
/ и * в определнии функции

Видели когда-нибудь вот такой синтаксис?

def foo(first, /, second, *, third):
print(first, second, third)


Выглядит странно?

На самом деле / и * навязывают положение ключевых и позиционных аргументов.

Попытаемся, например, вызвать foo() с неправильным набором параметров:

>>> foo("bar", "qux")
...
TypeError: foo() missing 1 required keyword-only argument: 'third'


Нужен keyword аргумент, окей, укажем все параметры:

>>> foo("bar", "baz", "qux")
...
TypeError: foo() takes 2 positional arguments but 3 were given


А, один из них по ключу:

>>> foo("bar", "baz", third="qux")
bar baz qux


Получилось!

Оба символа опциональны. И, в моем опыте, если ставят, то чаще только звездочку.

Источник: https://docs.python.org/3/tutorial/controlflow.html#special-parameters

🐠
Делюсь с вами коллективным учебником по машинному обучению из Яндекса. На самом деле наполовину делюсь, наполовину сохраняю себе, чтобы прочитать позже. Теплый привет Вите Кантору
У нас опять есть группа, можно покомментить и покидаться какашками

UPD Правила игры те же: нетоксично про питон, программирование, инфраструктуру и за жизнь. Но нужно быть пуськой.

UPD2 https://t.me/+CgNMmJwzjYI1MmYy
Работа import и структура проекта

Когда вы импортируете какой-то модуль в вашем коде, питон не учитывает, в каком файле этот импорт находится, влияет только то, как был запущен код.
Если модуль не был раньше загружен, питон пытается его найти по очереди в нескольких папках, которые можно посмотреть в переменной sys.path

По умолчанию она содержит примерно такие каталоги:
* каталог, добавляемый при запуске
* каталоги указанные в переменной окружения PYTHONPATH
* каталог текущего активированного виртуального окружения
* каталог установки python

1. Если вы запускаете ваш скрипт командой python scriptname.py, то первым в списке будет тот каталог, где находится запускаемый скрипт. Текущий каталог не имеет значения.
2. Если вы запускаете ваш код командой python -m packagename, то первым в списке будет текущий каталог. При запуске питон попытается найти и импортировать packagename по общим правилам.
3. Если вы запускаете код с помощью других инструментов вроде pytest, они тоже могут сами добавлять что-то в sys.path.

Скорее всего, вам не стоит самостоятельно менять sys.path, так как алгоритм его заполнения стандартный и привычен для всех. Если по каким-то причинам вас он не устраивает, возможно у вас неверная структура проекта.

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

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

1. Вынести запускаемые скрипты на верхний уровень, а остальной код упаковать в пакет.

Упаковка кода в пакет с уникальным именем позволяет исключить конфликты имен. А вынесение всех запускаемых файлов на один уровень делает состав sys.path предсказуемым.

Выглядеть это будет примерно так:

├── appname
│ ├── __init__.py
│ ├── other_module.py
│ └── some_module.py
├── cli_module.py
└── requirements.txt

2. Создать распространяемый пакет (рекомендую).

В этом случае вы упаковываете весь код в пакет, что помогает исключить конфликты имен.
Для запуска команд вы можете использовать синтаксис python -m appname.cli_module или заполнить секцию entry_points в файле с описанием проекта (setup.cfg, pyproject.toml), после чего иметь свои кастомные консольные команды. В обоих случаях вы сможете запускать код, находясь в любом каталоге, без необходимости указывать полные пути к файлам.

Для удобства разработки с таким подходом удобно устанавливать пакет в editable-режиме с помощью команды типа pip install -e .

Структура будет примерно такой:

├── pyproject.toml
└── src
└── appname
├── __init__.py
├── cli_module.py
├── other_module.py
└── some_module.py

Дополнительные материалы:
* https://packaging.python.org/en/latest/
* https://docs.python.org/3/reference/import.html
* https://docs.python.org/3/library/sys.html#sys.path
* https://ru.wikipedia.org/wiki/Рабочий_каталог
Сегодня в 18:00 UTC+2 релизят Python 3.11 в прямом эфире, смотреть можно по ссылке ниже:

https://www.youtube.com/watch?v=PGZPSWZSkJI

UPD: еще можно подписаться на их youtube, чтобы не пропускать релизы в будущем, если вам интересно
Фича f-строк, о которой вы не знали

Смотрите, вот обычная f-строка

>>> text = 'JUPI'
>>> print(f'{text}')
JUPI

Если я добавлю в нее
* двоеточие,
* символ-заполнитель,
* и укажу требуемую длину строки с помощью символа <

>>> print(f'{text:-<15}')

То не занятый текстом остаток строки будет заполнен выбранным символом:

JUPI-----------

Если указать длину строки через >, то можно заполнить строку с левой стороны:

>>> print(f'{text:->15}')
-----------JUPI

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

-----JUPI------

Подсказка: можно поискать вот здесь
🐠
Что такое JSON?

JSON (JavaScript Object Notation) – это удобный для чтения человеком и машиной структурированный формат, который используют для обмена данными.

JSON представляет собой наборы пар «ключ: значение» и основан на базе синтаксиса объектов JavaScript. При этом JSON считается независимым от JavaScript, так как может использоваться с любым языком программирования.

История

Создатель формата JSON – Дуглас Крокфорд, американский программист, принимающий активное участие в развитии JavaScript. В 2001 году, во время работы в своей компании State Software он разработал стандарт JSON как аналог формата XML, который уже существовал в тот момент.

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

Самое первое сообщение JSON было отправлено в 2001 году. Вот как оно выглядело:

<html><head><script>​
document.domain = 'fudco';
parent.session.receive({
to: "session",
do: "test",
text: "Hello world"
})
</script></head></html>


Это был html-документ, только небольшая часть которого напоминает современный JSON. Сначала этот формат был предназначен для языка JavaScript, но позже его стали использовать с другими языками программирования.

Через год Крокфорд купил домен JSON.org и опубликовал там синтаксис JSON с примерами реализации, и этот сайт до сих пор работает.

Какую задачу решает

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

Сериализация – это кодирование данных, превращение в серию байтов, их перенос в файл JSON с целью хранения или передачи по сети. Десериализация – обратный процесс распаковки данных.

JSON полезнее всего
- для создания приложений, взаимодействующих с браузером,
- там, где необходимо обмениваться информацией между серверами,
- и когда нужно передать структурированную информацию по сети.

Как выглядит JSON

JSON файл структурирован и состоит из пар ключ-значение:

{
"name": "John Smith",
"age": 35
}


Вот список типов данных, которые поддерживает JSON:
- Строка – несколько литералов, заключенных в кавычки.
- Число – целое или действительное.
- Массив – множество значений, заключенное в квадратные скобки.
- Логическое значение – true/false.
- Пустое значение​ – null.

Как работать с JSON

Сегодня в любом языке программирования есть встроенная библиотека или модуль для работы с JSON, и в Python тоже! Для начала работы достаточно подключить модуль json с помощью команды import:

import json

Сериализовать данные (например, словарь data) можно с помощью метода dump:

with open(“my_file.txt”, “w”) as file:
​json.dump(data, file)


При кодировании из Python в JSON данные меняют свой тип следующим образом:

dict -> Object
list-> Array
tuple -> Array
str -> String
int -> Number
float -> Number
True / False -> true / false
None -> null


Записать данные в строку можно, используя метод dumps(). Методы похожи, единственное отличие состоит в том, что вторым параметром не указывается файловый объект, так как на самом деле не происходит записи на диск. В файле с кодом все будет выглядеть подобным образом:

data_string = json.dumps(data)

Чтобы десериализовать файл, можно использовать методы load() и loads():

with open(“my_file.txt”, “r”) as file:
​ data = json.load(file)​


​Так же, как и при сериализации, происходит трансформация данных в характерный для языка программирования тип. При этом переход из JSON в Python не полностью аналогичен переходу из Python в JSON.

loads() идентичен dumps(), он также предназначен для работы со строкой.

Итого

- JSON – это в первую очередь человекочитаемый формат.
- Используется для передачи данных по сети и для клиент-серверного взаимодействия.
- Важные функции – это сериализация и десериализация, которые осуществляются методами dump() и load().
Канал переименован из Python in Depth в CoolPython
Все знают, что целочисленное деление округляет результат вниз. Например, если результат деления во float

5. / 3. = 1.66666667 то в целых числах он округлится вниз, а не к ближайшему целому: 5 // 3 = 1 А если результат отрицательный? - 5 // 3 = ?
Anonymous Quiz
8%
1
38%
-1
45%
-2
8%
Ошибка
Стек и очередь

Идеи стека и очереди часто встречаются в различных языках программирования. Давайте разберемся, в каких ситуациях их применение уместно и удобно программисту.

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

В программировании очередь работает аналогично. Очередь в программировании — это коллекция элементов, которые обрабатываются по принципу «первый зашел — первый вышел» (FIFO).

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

Стек работает по-другому. Стек – это тоже коллекция элементов, но работает он по принципу «последним зашел — первым вышел» (LIFO)

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

Частое применение стека в программировании – это организация записей об изменениях в файле или документе. Текстовые редакторы обычно записывают действия пользователя над файлом с помощью стека, чтобы потом можно было легко отменить эти действия в обратном порядке.

При работе со стеком и очередью нельзя обращаться к произвольному элементу в коллекции, потому что это нарушило бы принципы LIFO или FIFO. Чтобы добраться до нужного элемента, необходимо перебрать все элементы стоящие перед или после него в списке по установленному порядку.

В программировании стек и очередь часто используют для математических вычислений, для работы с данными и операциями. Принципы FIFO и LIFO позволяют нам структурировать и упорядочивать работу с данными. Такой подход позволяет быть уверенными, что данные и операции будут обрабатываться в нужном порядке.
Рассказали о разнице функций input и raw_input в Python2 в карточках. Читайте!

Карточки подготовили вместе с @pro_python_code