Парное программирование — это когда два программиста работают за одним компьютером.
Один пишет код, а другой наблюдает, предлагает улучшения и подмечает ошибки. Через полчаса-час они меняются ролями.
✅ Плюсы: улучшение качества кода, обмен знаниями, повышение сплочённости команды.
⛔️ Минусы: требует больше времени и ресурсов, может быть утомительным для участников.
Практика была предложена Кентом Беком, автором экстремального программирования.
🔍 Представьте, что вы новоиспечённый тимлид в команде разработки партнёрского кода Рекламной сети Яндекса.
Чтобы освоиться в новом проекте, вы выделяете время по утрам для парного программирования с разработчиками из команды.
Однажды утром вы торопитесь на эту встречу, а ваш коллега присылает вам сообщение:
* Это не выдуманная история, а моя личная, из практики. Ваня, привет, если ты вдруг это читаешь! 😁
🔗 https://ru.wikipedia.org/wiki/Парное_программирование
Один пишет код, а другой наблюдает, предлагает улучшения и подмечает ошибки. Через полчаса-час они меняются ролями.
✅ Плюсы: улучшение качества кода, обмен знаниями, повышение сплочённости команды.
⛔️ Минусы: требует больше времени и ресурсов, может быть утомительным для участников.
Практика была предложена Кентом Беком, автором экстремального программирования.
🔍 Представьте, что вы новоиспечённый тимлид в команде разработки партнёрского кода Рекламной сети Яндекса.
Чтобы освоиться в новом проекте, вы выделяете время по утрам для парного программирования с разработчиками из команды.
Однажды утром вы торопитесь на эту встречу, а ваш коллега присылает вам сообщение:
Олег, извини, я опаздываю. Начинай, пожалуйста, парно программировать без меня.
* Это не выдуманная история, а моя личная, из практики. Ваня, привет, если ты вдруг это читаешь! 😁
🔗 https://ru.wikipedia.org/wiki/Парное_программирование
😁15
Пост-знакомство
Меня зовут Олег Громов, и я приветствую тебя на канале Битмап!
🦸♂️ Я — человек-оркестр. Люблю проектировать и создавать полезные системы от начала и до конца. Мне неплохо даётся дизайн, написание текстов, маркетинговые активности и анализ их результатов. Умею нанимать и организовывать работу команды так, чтобы важные цели достигались, а людям было хорошо.
📝 Немного фактов обо мне
• Я тимлид команды AI tools и бэкендер в edtech-стартапе Oneday
• Живу в Лондоне, у меня Global Talent виза. Долго жил в Москве, гостил в Штатах и Швеции по полгода
• 3 года тимлидил в Яндексе в Рекламной сети, почти 2 года — в Toptal
• Провёл 200-250 собеседований разработчиков, немного дизайнеров и менеджеров. Сам прошёл (или провалил) порядка сотни
• Посмотрел на зарубежные бигтехи (Фейсбук, Klarna) и стартапы (Sourcegraph, Hook и пр.) изнутри
• Написал популярные статьи про удалёнку за доллары
• Запускаю разные сайд-проекты, включая этот канал
🔗 У меня есть сайт, линкедин, а также личный канал. А вот ссылки на мои перфомансы в интернете на русском и на английском.
❤️ Я даю платные личные консультации:
• развитие хард- и софт-скиллов, код-ревью
• планирование карьеры и релокация
• сайд-проекты
🏢 И для компаний:
• аудит веб-приложений, сайтов и их производительности
• аудит состояния кодовой базы
• помощь в настройке командных процессов и найма
• проведение собеседований
• создание и поддержка MVP
✅ Записаться по ссылке: https://forms.gle/MyqcJCxZ6Phhzzi47
Меня зовут Олег Громов, и я приветствую тебя на канале Битмап!
🦸♂️ Я — человек-оркестр. Люблю проектировать и создавать полезные системы от начала и до конца. Мне неплохо даётся дизайн, написание текстов, маркетинговые активности и анализ их результатов. Умею нанимать и организовывать работу команды так, чтобы важные цели достигались, а людям было хорошо.
📝 Немного фактов обо мне
• Я тимлид команды AI tools и бэкендер в edtech-стартапе Oneday
• Живу в Лондоне, у меня Global Talent виза. Долго жил в Москве, гостил в Штатах и Швеции по полгода
• 3 года тимлидил в Яндексе в Рекламной сети, почти 2 года — в Toptal
• Провёл 200-250 собеседований разработчиков, немного дизайнеров и менеджеров. Сам прошёл (или провалил) порядка сотни
• Посмотрел на зарубежные бигтехи (Фейсбук, Klarna) и стартапы (Sourcegraph, Hook и пр.) изнутри
• Написал популярные статьи про удалёнку за доллары
• Запускаю разные сайд-проекты, включая этот канал
🔗 У меня есть сайт, линкедин, а также личный канал. А вот ссылки на мои перфомансы в интернете на русском и на английском.
❤️ Я даю платные личные консультации:
• развитие хард- и софт-скиллов, код-ревью
• планирование карьеры и релокация
• сайд-проекты
🏢 И для компаний:
• аудит веб-приложений, сайтов и их производительности
• аудит состояния кодовой базы
• помощь в настройке командных процессов и найма
• проведение собеседований
• создание и поддержка MVP
✅ Записаться по ссылке: https://forms.gle/MyqcJCxZ6Phhzzi47
🔥11😁2❤1
Поиск в глубину (DFS) — алгоритм обхода графов и деревьев.
Начинает с корневого узла и двигается как можно глубже по каждой ветке. Потом возвращается назад и продолжает в ширину.
DFS применяют для поиска пути и циклов в графах, в топологической сортировке (например, для построения графа зависимостей).
⏳ Сложность по времени:
💾 По памяти:
🔥 Плюсы: просто реализовать, особенно рекурсивную версию. Работает на направленных и ненаправленных графах.
⛔️ Минусы: не всегда находит кратчайший путь.
📝 Пример реализации для графа в виде списка смежности:
🔗 https://ru.wikipedia.org/wiki/Поиск_в_глубину
Начинает с корневого узла и двигается как можно глубже по каждой ветке. Потом возвращается назад и продолжает в ширину.
DFS применяют для поиска пути и циклов в графах, в топологической сортировке (например, для построения графа зависимостей).
⏳ Сложность по времени:
O(V + E)
.💾 По памяти:
O(V)
.V
— количество вершин, E
— количество рёбер.🔥 Плюсы: просто реализовать, особенно рекурсивную версию. Работает на направленных и ненаправленных графах.
⛔️ Минусы: не всегда находит кратчайший путь.
📝 Пример реализации для графа в виде списка смежности:
def dfs(graph, start, visited=None):
visited = visited or set()
visited.add(start)
print(start)
for next in graph[start] - visited:
dfs(graph, next, visited)
return visited
graph = {
'A': {'B', 'C'},
'B': {'A', 'D', 'E'},
'C': {'A', 'F'},
'D': {'B'},
'E': {'B', 'F'},
'F': {'C', 'E'}
}
dfs(graph, 'A')
🔗 https://ru.wikipedia.org/wiki/Поиск_в_глубину
👍6
Lean startup — способ работы над стартапом, когда команда проходит следующий цикл, пока не найдёт работающий продукт:
1️⃣ выдвинули измеримую гипотезу, обновили продукт
2️⃣ запустили обновлённый MVP, показали пользователям, измерили результаты
3️⃣ сделали выводы и вернулись в п.1
Методология была предложена и популяризована с выходом одноимённой книжки Eric Ries в 2011 году.
🚀 Плюсы: ускоряет вывод продукта на рынок. Поощряет регулярный сбор обратной связи от клиентов.
😞 Минусы: MVP могут не давать достаточно ценности клиентам. В череде пивотов легко потерять стратегию и видение (vision).
Важно уметь привлекать пользователей и трафик по доступной цене, чтобы собирать полезную ОС на каждой итерации.
📝 Например, Dropbox творчески использовали этот подход, чтобы подтвердить спрос на свой продукт.
Команде было сложно построить даже едва работающий прототип, поэтому они записали видео-демо — и за ночь привлекли 70 тысяч человек в список ожидания.
🔗 https://ru.wikipedia.org/wiki/Бережливый_стартап
1️⃣ выдвинули измеримую гипотезу, обновили продукт
2️⃣ запустили обновлённый MVP, показали пользователям, измерили результаты
3️⃣ сделали выводы и вернулись в п.1
Методология была предложена и популяризована с выходом одноимённой книжки Eric Ries в 2011 году.
🚀 Плюсы: ускоряет вывод продукта на рынок. Поощряет регулярный сбор обратной связи от клиентов.
😞 Минусы: MVP могут не давать достаточно ценности клиентам. В череде пивотов легко потерять стратегию и видение (vision).
Важно уметь привлекать пользователей и трафик по доступной цене, чтобы собирать полезную ОС на каждой итерации.
📝 Например, Dropbox творчески использовали этот подход, чтобы подтвердить спрос на свой продукт.
Команде было сложно построить даже едва работающий прототип, поэтому они записали видео-демо — и за ночь привлекли 70 тысяч человек в список ожидания.
🔗 https://ru.wikipedia.org/wiki/Бережливый_стартап
👍3
Same-origin policy (SOP) — механизм безопасности в браузерах, который частично запрещает обмен данными между разными origin.
Origin — это комбинация
📚 Допустим, вы залогинились в
Если бы не SOP, браузер сделал бы этот запрос, отправив вместе с ним cookies, а значит потенциально выполнил бы запрос на перевод денег от вашего лица.
⚠️ Кроме этого, SOP также запрещает читать чужие cookies из JS, получать доступ к
SOP появился в Netscape Navigator 2 вместе с первой версией JavaScript ещё в 1995 году.
А уже спустя много лет появился
🔗 https://developer.mozilla.org/ru/docs/Web/Security/Same-origin_policy
Origin — это комбинация
(protocol, hostname, port)
. Например, evil.com
и bank.ru
— разные origin, т.к. у них разный домен.📚 Допустим, вы залогинились в
bank.ru
, а потом открыли evil.com
. Его владелец вставил следующий скрипт:fetch('http://bank.ru/transfer?amount=100000&to=<evil_account>', {method: 'POST'})
Если бы не SOP, браузер сделал бы этот запрос, отправив вместе с ним cookies, а значит потенциально выполнил бы запрос на перевод денег от вашего лица.
⚠️ Кроме этого, SOP также запрещает читать чужие cookies из JS, получать доступ к
window
и прочим внутренностям чужих сайтов, вставленных в iframe
и кучу других мелочей.SOP появился в Netscape Navigator 2 вместе с первой версией JavaScript ещё в 1995 году.
А уже спустя много лет появился
CORS
, Cross-origin Resource Sharing, который позволяет обойти SOP.🔗 https://developer.mozilla.org/ru/docs/Web/Security/Same-origin_policy
🔥14👍2
JSON5 — это расширение формата JSON, которое поддерживает:
• комментарии
• висячие запятые в массивах и объектах:
• строки в одинарных кавычках:
• ключи без кавычек, если это валидные JS-идентификаторы
• перенос строк с помощью
• 16-ричные числа:
• пропущенный ноль в десятичных дробях:
• плюс в положительных числах
•
Для поддержки
Несмотря на более удобный синтаксис, JSON5 нечасто встречается в дикой природе, а некоторые и вовсе относятся к нему крайне скептически.
📝 Так выглядит пример JSON5:
🔗 https://json5.org/
• комментарии
/* */
и //
• висячие запятые в массивах и объектах:
[1,2,]
• строки в одинарных кавычках:
'bitmap'
• ключи без кавычек, если это валидные JS-идентификаторы
• перенос строк с помощью
\
в конце строки вместо \n
• 16-ричные числа:
0xCOFFEE
• пропущенный ноль в десятичных дробях:
.41468
• плюс в положительных числах
+3.14
•
Infinity
, -Infinity
и NaN
, как в IEEE 754
Для поддержки
JSON5
нужны сторонние библиотеки, например, json5 для node или json5 для python.Несмотря на более удобный синтаксис, JSON5 нечасто встречается в дикой природе, а некоторые и вовсе относятся к нему крайне скептически.
📝 Так выглядит пример JSON5:
{
// видали, как можно
bitmap18: 'твой любимый "cловарик"'
yo: "Привет! \
Уже рассказал друзьям о @bitmap18?",
i_love: 0xCOFFEE,
syntax_sugar: [.41468, +1, ],
}
🔗 https://json5.org/
👍9😁3🤔1
SELECT FOR UPDATE
— способ избежать состояния гонки (race condition) и взаимных блокировок в UPDATE
, исполняющихся одновременноюПоддерживается в Postgres, MySQL c InnoDB, Oracle.
📚 Например, пользователь покупает товары
1
и 4
в интернет магазине, и нам надо обновить остатки в БД:BEGIN;
SELECT *
FROM product_qty
WHERE product_id IN (1,4)
ORDER BY product_id
FOR UPDATE;
UPDATE product_qty
SET qty = qty - 1
WHERE product_id IN (1,4);
COMMIT;
🎯 Как это работает:
1️⃣ начинаем транзакцию
2️⃣ делаем
SELECT ... FOR UPDATE
: обновляем несколько строк, значит нужно использовать ORDER BY
3️⃣ дальше обычный
UPDATE
4️⃣ наконец,
COMMIT
, чтобы завершить транзакцию и снять блокировкиБез
ORDER BY
в п.2 одновремено исполняющиеся транзакции могут попытаться взять блокировки в разном порядке, что может привести к дедлоку.⚠️ В зависимости от уровня изоляции транзакций, другие
SELECT
без FOR UPDATE
могут получить устаревшие значения.🔗 https://ru.wikipedia.org/wiki/Select_for_update
👍13
Транзистор — полупроводниковый компонент, который используется для усиления и преобразования аналоговых сигналов (например, звука), а также в качестве переключателя (ключа, switch) для цифровых сигналов.
📅 Изобретен в 1947 году в Bell Labs тремя учеными: Джоном Бардином, Уолтером Браттейном и Уильямом Шокли.
Транзисторы пришли на замену менее надёжным и более громоздким вакуумным лампам, что позволило создать всю современную электронику — от простейших радио до самых современных миниатюрных процессоров.
🥇 Его создатали получили за своё изобретение Нобелевскую премию по физике в 1956 году.
Количество транзисторов в процессорах увеличилось от всего 2,250 штук в Intel 4004, выпущенном в 1971 году, до сотен миллиардов в самых современных процессорах.
Их размеры за это же время уменьшились до всего лишь десятков атомов: транзистор произведённый по 5-нм техпроцессу имеет размер около 70 атомов в ширину.
А вот как выглядит первый в мире транзистор ⬇️
🔗 https://www.youtube.com/watch?v=xvrjIJw3OSU
📅 Изобретен в 1947 году в Bell Labs тремя учеными: Джоном Бардином, Уолтером Браттейном и Уильямом Шокли.
Транзисторы пришли на замену менее надёжным и более громоздким вакуумным лампам, что позволило создать всю современную электронику — от простейших радио до самых современных миниатюрных процессоров.
🥇 Его создатали получили за своё изобретение Нобелевскую премию по физике в 1956 году.
Количество транзисторов в процессорах увеличилось от всего 2,250 штук в Intel 4004, выпущенном в 1971 году, до сотен миллиардов в самых современных процессорах.
Их размеры за это же время уменьшились до всего лишь десятков атомов: транзистор произведённый по 5-нм техпроцессу имеет размер около 70 атомов в ширину.
А вот как выглядит первый в мире транзистор ⬇️
🔗 https://www.youtube.com/watch?v=xvrjIJw3OSU
👍11
🤗 На прошлой неделе мы писали про:
- Задача двух генералов
- Сериализация
- Парное программирование
- DFS
- Lean-стартап
- Same-origin policy
- JSON5
- SELECT FOR UPDATE
- Транзистор
❤️🔥 Может, уже что-то пригодилось?
- Задача двух генералов
- Сериализация
- Парное программирование
- DFS
- Lean-стартап
- Same-origin policy
- JSON5
- SELECT FOR UPDATE
- Транзистор
❤️🔥 Может, уже что-то пригодилось?
🔥6👍2
Десериализация — воссоздание объекта или структуры данных в памяти из его представления в виде строки байт/символов. Обратный сериализации процесс.
В отличие от парсинга, который обычно работает на произвольных входных данных — например, создаёт
Очевидно, что JSON или XML не ограничивают схему — потребуется
🔍 Или можно попробовать взять
Скомпилируем его для использования в python:
А затем десериализуем строку байт в объектное представление этого типа:
🔗 https://ru.wikipedia.org/wiki/Десериализация
В отличие от парсинга, который обычно работает на произвольных входных данных — например, создаёт
AST
(abstract syntax tree) из исходного кода, десериализация чаще подразумевает использование определённой схемы.Очевидно, что JSON или XML не ограничивают схему — потребуется
JSON Schema
или подобное решение.🔍 Или можно попробовать взять
protobuf
, где типы обязательны. Создадим вот такой channel.proto
:syntax = "proto3";
message Channel {
string handle = 1;
int32 subscribers = 2;
}
Скомпилируем его для использования в python:
protoc channel.proto --python_out=.
А затем десериализуем строку байт в объектное представление этого типа:
import channel_pb2
channel = channel_pb2.Channel()
channel.ParseFromString(b'\n\x07@bitmap\x10\x90N')
print(channel)
# handle: "@bitmap"
# subscribers: 10000
🔗 https://ru.wikipedia.org/wiki/Десериализация
👍2
Суррогатный ключ — сгенерированный уникальный идентификатор строки в реляционной БД.
💎 Зачем они нужны?
Скажем, в таблице
•
•
• комбинация
⛔️ Натуральные ключи имеют недостатки:
• при обновлении ключа придётся обновлять и связанные таблицы
• требования к уникальности меняются: бизнес может разрешить разным клиентам использовать один
• их опасно использовать в публичных URL, API и т.п.
✅ Лучше использовать суррогатные ключи, никак не связанные с данными в таблице:
• они гарантированно уникальны
• просты в использовании
• не меняются вместе с данными
• индексы по ним обычно работают быстрее
📖 Суррогатный ключ можно сделать из монотонно растущего
Или же взять рандомный или около-рандомный идентификатор, например, UUID.
🔗 https://ru.wikipedia.org/wiki/Суррогатный_ключ
💎 Зачем они нужны?
Скажем, в таблице
Users
натуральным ключом может быть:•
email
или phone
•
username
• комбинация
first_name, last_name, birthday
⛔️ Натуральные ключи имеют недостатки:
• при обновлении ключа придётся обновлять и связанные таблицы
• требования к уникальности меняются: бизнес может разрешить разным клиентам использовать один
email
или телефон• их опасно использовать в публичных URL, API и т.п.
✅ Лучше использовать суррогатные ключи, никак не связанные с данными в таблице:
• они гарантированно уникальны
• просты в использовании
• не меняются вместе с данными
• индексы по ним обычно работают быстрее
📖 Суррогатный ключ можно сделать из монотонно растущего
INTEGER
:
CREATE TABLE Users (
user_id SERIAL PRIMARY KEY,
username VARCHAR(255),
email VARCHAR(255) NOT NULL,
);
Или же взять рандомный или около-рандомный идентификатор, например, UUID.
🔗 https://ru.wikipedia.org/wiki/Суррогатный_ключ
👍8
Пивот (pivot) — это серьёзное изменение в бизнес-модели или стратегии стартапа.
👌 Пивоты совершают стартапы, когда изначальная идея не приносит ожидаемых результатов. Обычно это затрагивает:
• продукт и его позиционирование
• целевую аудиторию
• способ привлечения и удержания клиентов
Пивоты важно совершать вовремя, пока есть ресурсы, и на основе обратной связи от реальных пользователей.
🔑 Ключевая задача разработки: уметь быстропревращать продукт из ужа в ежа и докатывать изменения до пользователей.
📚 Например, ваш стартап изначально делал приложение для фитнеса, ориентированное на профессиональных спортсменов.
После анализа рынка и обратной связи от пользователей команда решает изменить фокус на более широкую аудиторию любителей фитнеса, добавляя функции, такие как отслеживание активности и персонализированные планы тренировок.
Если это изменение позволяет привлечь новых пользователей, а юнит-экономика при этом сходится, его можно считать успешным.
🔗 https://ru.wikipedia.org/wiki/Пивот
👌 Пивоты совершают стартапы, когда изначальная идея не приносит ожидаемых результатов. Обычно это затрагивает:
• продукт и его позиционирование
• целевую аудиторию
• способ привлечения и удержания клиентов
Пивоты важно совершать вовремя, пока есть ресурсы, и на основе обратной связи от реальных пользователей.
🔑 Ключевая задача разработки: уметь быстро
📚 Например, ваш стартап изначально делал приложение для фитнеса, ориентированное на профессиональных спортсменов.
После анализа рынка и обратной связи от пользователей команда решает изменить фокус на более широкую аудиторию любителей фитнеса, добавляя функции, такие как отслеживание активности и персонализированные планы тренировок.
Если это изменение позволяет привлечь новых пользователей, а юнит-экономика при этом сходится, его можно считать успешным.
🔗 https://ru.wikipedia.org/wiki/Пивот
👍5😁4
Stack overflow — ошибка, когда программа пытается использовать больше памяти на стеке, чем разрешено операционной системой.
📌 Обычно случается при:
• слишком большой глубине рекурсивных вызовов
• большом количестве локальных переменных
📖 Например, на моей MacOS максимальная глубина стека — 8172 Кб (
Скомпилируем простейшую программу:
без оптимизаций (
Программа попыталась занять больше памяти на стеке, чем разрешено ОС, и была завершена.
Если увеличить размер стека, например, до 16 Мб (
А если включить оптимизации через флаг
🔗 https://en.wikipedia.org/wiki/Stack_overflow
📌 Обычно случается при:
• слишком большой глубине рекурсивных вызовов
• большом количестве локальных переменных
📖 Например, на моей MacOS максимальная глубина стека — 8172 Кб (
ulimit -s
). Если какая-то программа попробует использовать больше, ОС прервёт её выполнение. Скомпилируем простейшую программу:
#include <stdio.h>
void go(int n) {
printf("%d\n", n);
go(n + 1);
}
int main() {
go(1);
return 0;
}
без оптимизаций (
gcc -o test test.c
) и запустим:
...
261471
[1] 78367 segmentation fault ./test
Программа попыталась занять больше памяти на стеке, чем разрешено ОС, и была завершена.
Если увеличить размер стека, например, до 16 Мб (
ulimit -s 16384
), то ошибка случится позже. А если включить оптимизации через флаг
-O2
в gcc
, то она сможет работать бесконечно, т.к. комплиятор "развернёт" рекурсию в цикл — cм. комментарии.🔗 https://en.wikipedia.org/wiki/Stack_overflow
🔥5
sort — это утилита в unix-подобных ОС для сортировки строчек в текстовых файлах.
🧩 Полезные ключи:
•
•
•
•
•
📚 Возьмём файл с заказами
Отсортируем по цене:
По фамилии:
🌟 Как и другие
Например, отсортируем заказы по
🔗 https://ru.wikipedia.org/wiki/Sort_(Unix)
🧩 Полезные ключи:
•
-t,
— указать разделитель колонок ,
•
-k5,5
— сортировка по 5-й колонке•
-n
— числовая, а не лексикографическая (алфавитная) сортировка•
-g
— поддержка чисел с плавающей запятой•
-r
— обратная сортировка📚 Возьмём файл с заказами
orders.csv
:id,fname,lname,pid,qty,date,addr,price
1,Иван,Иванов,101,2,2024-09-01,Ленина 123,4000
2,Анна,Смирнова,202,1,2024-09-02,Пушкина 45,1999
3,Борис,Петров,303,3,2024-09-03,Гоголя 78,5998
4,Ольга,Кузнецова,404,1,2024-09-04,Чехова 90,2999
5,Алексей,Морозов,505,2,2024-09-05,Толстого 123,5000
Отсортируем по цене:
sort -t, -k8,8nr orders.csv
.По фамилии:
LC_ALL=C.UTF-8 sort -t, -k3,3 orders.csv
.LC_ALL=C.UTF-8
необходим для поддержки юникода.🌟 Как и другие
unix
-утилиты, sort
удобно объединять с другими командами через |
.Например, отсортируем заказы по
pid
и возьмём только 3 поля: sort -t, -k4,4 orders.csv | cut -d, -f4,3,8
🔗 https://ru.wikipedia.org/wiki/Sort_(Unix)
👍6
hash
в python позволяет получить хэш любого неизменяемого объекта, например, int
, float
, строки или tuple
.Скажем,
hash('@bitmap18 лучше всех') == -952311228443755449
. 🎯 Используется в словарях (
dict
), чтобы определить, где хранится значение (в каком bucket
) для ключа, и множествах (set
), чтобы понять, есть ли в нём данный ключ.Также можно определить дандер-метод
__hash__
для любого класса.📖 Скажем, у нас есть класс
Customer
, и хочется создать список пользователей без дубликатов. Для этого отлично подойдёт
set()
:class Customer:
def __init__(self, id, email):
self.id = id
self.email = email
def __hash__(self):
return self.id
customers: Iterable[Customer] = get_customers()
unique_customers = set(customers)
Без заданного
Customer.__hash__
получилось бы создать set
, только используя идентификаторы напрямую:unique_customers = set(c.id for c in customers)
Что, конечно, менее элегантно.
🔗 https://www.programiz.com/python-programming/methods/built-in/hash
👍5