Коробка с питоном
530 subscribers
49 photos
128 links
Заметки от Python-разработчика: сниппеты, обзоры пакетов, новости и другая полезная информация.
Download Telegram
Множества, в отличии от последовательностей неупорядоченные, элементы в нём уникальны. Поговорим про изменяемые множества.
Допустим, я хочу сделать изменяемое множество из моих братишек-разработчиков (привет!):
>>> bros = {"cmd410", "reygasai", "mo_rjindael"}
>>> bros
{'mo_rjindael', 'cmd410', 'reygasai'}

Добавим ещё одного братишку:
>>> bros.add("hkc")
>>> bros
{'mo_rjindael', 'cmd410', 'reygasai', 'hkc'}

Попытаемся добавить 'cmd410' ещё раз в множество:
>>> bros.add("cmd410")
>>> bros
{'mo_rjindael', 'cmd410', 'reygasai', 'hkc'}

Множество не изменилось, потому что 'cmd410' уже в нём есть. Элементы в множестве уникальны.
Это можно использовать для того, чтобы убрать повторяющиеся элементы в списке:
>>> repeated = [1, 1, 2, 3, 4, 1, 2, 3, 4, 4]
>>> set(repeated)
{1, 2, 3, 4}

Множество неупорядоченно. Например, мы не можем взять нулевого по индексу братишку из него:
>>> bros[0]
TypeError: 'set' object is not subscriptable.

А какие ещё операции над множествами вы знаете? Пишите в комментарии 😏!
#std
Использование распаковки для исключения лишних элементов

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

>>>record = ('kiriharu', '[email protected]', '8-800-555-35-35', '1337-1337')
>>>get_phones(record)
['8-800-555-35-35', '1337-1337']

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

>>>grades = ('kiriharu', 1, 1, 1, 1, 'A')
>>>get_grades(grades)
[1, 1, 1, 1]

Выражение со звездочкой можно использовать как угодно - можно наоборот отбросить всё то, что попадает в него, а остальное вернуть. Попробуйте сами написать такую функцию :)

Код на GitHub
#std
Несколько методов для эмуляции числовых типов

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

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

>>> v1 = Vector2D(1, 1)
>>> v2 = Vector2D(5, 6)
>>> v1 + v2
Vector(6, 7)
>>> v1 * 3
Vector(3, 3)

GitHub
#std
Коробка с питоном
Несколько методов для эмуляции числовых типов В питоне есть магические методы, которые позволяют складывать или умножать между собой объекты. Рассмотрим их. Например, мы можем сделать класс для представления двухмерных векторов, которые могут складываться…
Возвращайте NotImplemented для неподдерживаемых бинарных операций с вашим типом

В комментариях к предыдущему посту возник вопрос, что если вместо целочисленного scalar к нам придет float или какой-то другой тип?

Естественно, код в посте выше будет работать с ошибками, поэтому явно было бы выбросить исключение, но оказывается что так делать не нужно!

Оказывается, в Python есть следующий механизм: если метод представляющий бинарную операцию (__add__, __mul__ и т.д.) возвращает NotImplemented, то Python попытается произвести отраженную операцию (для x.__mul__(1) вызовет 1.__rmul__(x), например) или другие операции, в зависимости от оператора. Как только все возможные методы вернут NotImplemented он сам возбудит исключение на месте вызова метода в вашем коде, а не в коде класса:

>>> v1 = Vector2D(1, 2)
>>> v1 * 1.1
TypeError: unsupported operand type(s) for *: 'Vector2D' and 'float'

Списки магических методов и рекомендации по их реализации можно найти в разделе Data model

GitHub | Объяснение "на пальцах"
#std
💫 Небольшой новостной пост

Ранее, разработчик FastAPI - Sebastian 'tiangolo' Ramirez говорил о интеграции pydantic (библиотека для валидации и де/сериализации данных на основе аннотаций типов) и sqlalchemy (одна из самых популярных ORM для взаимодействия с реляционными базами данных). И кажется, это свершилось.

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

#новости
adict - небольшая библиотека, которая позволяет обращаться со словарем так, как будто мы взаимодействуем с экземпляром класса. Библиотека предоставляет доступ к ключам словаря как доступ к атрибутам объекта.

GitHub | PyPi
#библиотека
Как работает bool()?

Python может принимать любой объект в булевом контексте. Чтобы определить, является ли выражение истинным или ложным, применяется функция bool(x), которая должна вернуть булево значение (True или False).

По умолчанию, объект попытается вызвать метод __bool__, который должен вернуть булево значение. Если реализованного метода нет, то Python попытается вызвать __len__, который должен вернуть 0 или значение больше ноля - при ноле результатом будет False, соответственно при значении больше ноля - True. Если ни один метод не реализован, то автоматически вернется True.

Резюмируя, получается такая цепочка: __bool____len__True
#std
Немного фактов про str() и repr()

- repr() вызывает метод __repr__ объекта, а метод str(), собственно __str__.
- repr() вызывается интерактивной оболочкой, при попытке вывести объект.
- Если метод __str__ в объекте не определен, то вызывается __repr__.

А что вы можете сказать про str() и repr()? Пишите ниже, в комментарии 👇
#std
Коробка с питоном
Немного фактов про str() и repr() - repr() вызывает метод __repr__ объекта, а метод str(), собственно __str__. - repr() вызывается интерактивной оболочкой, при попытке вывести объект. - Если метод __str__ в объекте не определен, то вызывается __repr__. …
Когда использовать __str__ или __repr__?

Оба магических метода используются для получения строкового представления объекта. Но как их лучше использовать - можно увидеть на картинке.

Таким образом имеем, что __repr__ должен использоваться для предоставлении информации об объекте разработчику, а __str__ должен быть читаемым и использоваться для представления информации пользователю.
#std
This media is not supported in your browser
VIEW IN TELEGRAM
glQiwiApi - асинхронная обертка для API QIWI и YooMoney.

Позволяет проверять баланс и транзакции, отправлять деньги и даже считать комиссию при отправке. Очень подойдет, если вы хотите (например) сделать прием платежей в Telegram боте.

GitHub | Docs | PyPi
#библиотека
Думаю, не будет лишним каждый месяц подводить итоги, поэтому, итоги августа:

🗒 Заметки:
- По возможности используйте специальные (магические) методы
- Про namedtuple
- Последовательности
- Изменяемые множества
- Использование распаковки для исключения лишних элементов
- Несколько методов для эмуляции числовых типов
- Возвращайте NotImplemented для неподдерживаемых бинарных операций с вашим типом
- Как работает bool()?
- Немного фактов про str() и repr()

📰 Новости:
- На свет появился репозиторий sqlmodel

📚Библиотеки:
- adict

Не забывайте просматривать комментарии и комментируйте старые записи, информация которая здесь есть пытается быть актуальной всегда 😉!

#август #2021
Коробка с питоном pinned «Думаю, не будет лишним каждый месяц подводить итоги, поэтому, итоги августа: 🗒 Заметки: - По возможности используйте специальные (магические) методы - Про namedtuple - Последовательности - Изменяемые множества - Использование распаковки для исключения лишних…»
В канале недавно уже был пост про namedtuple, но мне ещё есть что про него рассказать.

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

>>> lst = ['Mining', 'Excavating', 'Boiling']
>>> Skills = namedtuple('Skills', lst)
>>> skills = Skills(1, 2, 3)
>>> skills
Skills(Mining=1, Excavating=2, Boiling=3)

Ещё мы можем создать кортеж через метод _make():

>>> skills = Skills._make([1, 2, 3])
Skills(Mining=1, Excavating=2, Boiling=3)

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

Именованные кортежи неизменяемые, но мы можем использовать метод _replace(), чтобы изменить данные. Под капотом он использует метод _make для создания нового кортежа, поэтому, по сути, мы просто пересоздадим кортеж:

>>> skills._replace(Mining=100)
Skills(Mining=100, Excavating=2, Boiling=3)
#std
Коробка с питоном
В канале недавно уже был пост про namedtuple, но мне ещё есть что про него рассказать. Первое, что я хотел бы вам показать - именованный кортеж можно создать с помощью любой структуры данных, которая поддерживает итерирование: >>> lst = ['Mining', 'Excavating'…
В комментариях спросили, почему используются методы которые начинаются с нижнего подчеркивания, так как так принято обозначать приватные методы класса (которые не доступны пользователям). Ответ прост - соглашение об именах начинающихся со знака подчёркивания здесь имеет другое значение. Методы с нижним подчеркиванием являются вспомогательными, а проименованы они так чтобы избежать коллизий имён с полями кортежа.
А мы вернемся к нашим методам.

Метод _asdict() создаст словарь из именованного кортежа и вернет его:

>>> skills._asdict()
{'Mining': 1, 'Excavating': 2, 'Boiling': 3}

Ещё один полезный метод - _fields(). Он вернет кортеж из полей. Очень полезно, если вы хотите создать ещё один именованный кортеж:

>>> AllSkills = namedtuple('AllSkills', Skills._fields + ('Taming', 'Woodcutting'))
>>> AllSkills._fields
('Mining', 'Excavating', 'Boiling', 'Taming', 'Woodcutting')
Типизация именованных кортежей.

Один из комментаторов указал, что namedtuple() объявлен устаревшим и в 3.10 его поддержка прекратится. Что же делать? Использовать NamedTuple, если в вашем проекте питон выше версии 3.6.

Именованный кортеж можно создать 2 путями - через наследование NamedTuple (класс Skills) или старым способом (AnotherSkills). Оба способа содержат аннотации типов, повышающие (как минимум) читаемость кода.
Все методы, которые были в namedtuple (_make(), _replace(), _asdict()) работают:

>>> s = Skills(0)
>>> s._asdict()
{'mining': 0, 'excavating': 1}

Теперь мы можем посмотреть на аннотации:

s.__annotations__
{'mining': <class 'int'>, 'excavating': <class 'int'>}

Так же, ничего не мешает добавлять новые методы или оверрайтить существующие. В примере у Skills переопределен метод для str():

>>>str(s)
'Какой качок, уровень копания: 0\nуровень лесорубства: 100'

GitHub
#std
Про применение all()

Стандартная библиотека Python полна полезных вещей, но полезные вещи есть даже среди встроенных функций. Одна из таких встроенных функций - это all().

Функция all() возвращает True, если все элементы истинные (или объект пустой).

К примеру, all() очень удобно использовать с генераторами. Например, мы можем проверить, являются ли все октеты в IP-адресе числами:

>>> all(i.isdigit() for i in '127.0.0.b'.split('.'))
False
>>> all(i.isdigit() for i in '127.0.0.1'.split('.'))
True
#std
orjson - самая быстрая библиотека для (де)сериализации json, написанная на Rust.

Умеет нативно сериализовать объекты из dataclass, datetime, numpy и UUID. Имеет множество опций для тонкой настройки парсера, содержит вещи которых нет в парсере стандартной библиотеки. Имеет более полное соответствие UTF-8 и JSON формату.

PyPi | GitHub | Бенчмарки
#библиотека
Поиск N максимальных или минимальных элементов.

Если вы хотите создать список из N максимальных или минимальных элементов, модуль heapq вам поможет в этом.
У этого модуля есть две функции: nlargest() и nsmallest(), которые, соответственно ищут максимальные и минимальные элементы. Например:

>>> nums = [10, 20, 30, 40, 55, 632, -3, 98321, 82, 0, 8]
>>> heapq.nlargest(4, nums)
[98321, 632, 82, 55]
>>> heapq.nsmallest(4, nums)
[-3, 0, 8, 10]

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

currency = [
dict(name="Etherium", price=3323),
dict(name="Bitcoin", price=45538),
dict(name="ZCash", price=132),
dict(name="Litecoin", price=184),
dict(name="OmiseGo", price=8.933)
]

>>> heapq.nsmallest(2, currency, key=lambda s: s['price'])
[{'name': 'OmiseGo', 'price': 8.933}, {'name': 'ZCash', 'price': 132}]
>>> heapq.nlargest(2, currency, key=lambda s: s['price'])
[{'name': 'Bitcoin', 'price': 45538}, {'name': 'Etherium', 'price': 3323}]
#std
Определяем наиболее часто встречающиеся элементы в последовательности.

Допустим, у нас есть некоторая последовательность из слов (words), и мы хотим узнать, какие элементы в ней встречаются чаще остальных.

Для этого можно использовать класс Counter из модуля collections в котором есть метод most_common(), который и выдаст список элементов, которые встречаются чаще остальных.

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

>>>counts['test']
2

Кстати, эта задача часто встречается на собеседованиях и просят её реализовать без модуля collections. Как бы вы её решили? Ответы можете писать в комментарии, обсудим.
#std