Вам нужно реализовать декоратор
@thread_safe_cached
, который:- Кэширует результат вызова функции по её аргументам (аналог
functools.lru_cache
, но свой).- Если несколько потоков одновременно вызывают функцию с одинаковыми аргументами:
- Только один поток реально выполняет функцию,
- Остальные ждут, пока результат будет вычислен, и получают готовый результат.
- Кэш никогда не удаляется (неограниченный размер).
Ограничения:
- Решение должно работать для произвольных функций и аргументов (hashable).
- Нельзя использовать готовый
functools.lru_cache
или другие библиотеки кэширования.- Нужно обеспечить корректную работу в многопоточной среде без гонок данных.
---
▪️ Подсказки:
- Для кэширования подойдёт
dict
с ключами по аргументам (`*args`, `**kwargs`).- Для защиты доступа к кэшу понадобится
threading.Lock
.- Для ожидания завершения вычисления другими потоками можно использовать
threading.Event
.- Продумайте carefully: как отличить "результат уже посчитан" от "результат в процессе вычисления".
---
▪️ Что оценивается:
- Умение работать с многопоточностью в Python.
- Правильная организация кэширования.
- Чистота и лаконичность кода.
- Умение обрабатывать тонкие случаи, например: одновременные вызовы.
---
▪️ Разбор возможного решения:
Основная идея:
- Создать кэш
cache: Dict[Key, Result]
.- Одновременно создать словарь "ожиданий"
in_progress: Dict[Key, threading.Event]
.- Если кто-то начал считать значение:
- Остальные ждут
Event
, пока оно не будет установлено.Пример реализации:
import threading
import functools
def thread_safe_cached(func):
cache = {}
in_progress = {}
lock = threading.Lock()
@functools.wraps(func)
def wrapper(*args, **kwargs):
key = (args, frozenset(kwargs.items()))
with lock:
if key in cache:
return cache[key]
if key not in in_progress:
in_progress[key] = threading.Event()
in_progress[key].clear()
creator = True
else:
creator = False
if creator:
try:
result = func(*args, **kwargs)
with lock:
cache[key] = result
finally:
in_progress[key].set()
with lock:
del in_progress[key]
return result
else:
in_progress[key].wait()
with lock:
return cache[key]
return wrapper
---
▪️ Пояснения к коду:
- При первом вызове для новых аргументов поток создаёт
Event
и начинает считать результат.- Остальные потоки видят
Event
и вызывают wait()
, пока первый поток не установит set()
.- Как только результат посчитан,
Event
сигнализирует всем ждущим потокам, что данные готовы.- Доступ к
cache
и in_progress
защищён через lock
для избежания гонок.---
▪️ Возможные подводные камни:
- ❗ Если не удалять
Event
из in_progress
, кэш постепенно раздуется мусором.- ❗ Если ошибка случится внутри
func
, необходимо всё равно освободить Event
, иначе потоки будут вечно ждать.- ❗ Нельзя держать
lock
во время выполнения тяжёлой функции func
, иначе все потоки будут блокироваться.---
▪️ Вопросы на собеседовании по этой задаче:
- Как изменить реализацию, чтобы кэш имел ограничение по размеру (например, максимум 1000 элементов)?
- Как адаптировать декоратор под асинхронные функции (`async def`)?
- Что будет, если
func
иногда бросает исключения? Как кэшировать ошибки или не кэшировать их?- Как изменить реализацию так, чтобы кэш удалял устаревшие данные через TTL (Time-To-Live)?
---
@pythonl
Please open Telegram to view this post
VIEW IN TELEGRAM
⚡️ snnTorch — нейросети, которые работают как мозг. Этот проект предлагает необычный подход к машинному обучению, используя импульсные нейронные сети вместо классических искусственных нейронов.
Инструмент передает информацию через импульсы, что ближе к принципам работы биологического мозга. Библиотека построена на PyTorch и позволяет обучать такие сети с помощью обратного распространения ошибки, используя специальные суррогатные градиенты.
🤖 GitHub
@pythonl
Инструмент передает информацию через импульсы, что ближе к принципам работы биологического мозга. Библиотека построена на PyTorch и позволяет обучать такие сети с помощью обратного распространения ошибки, используя специальные суррогатные градиенты.
🤖 GitHub
@pythonl
Хочешь понять, твое ли аналитика — без курсов, затрат и лишнего стресса?
🔍 Пройди кейс-тест на реальной бизнес-задаче — всё, как в работе настоящего аналитика, но без необходимости иметь профильные навыки. Только мышление, логика и внимательность.
⚡️ Всего 10 конкретных вопросов — от постановки цели до финальных выводов. За 60 минут: — получишь реальные вводные от "коллег",
— прокачаешь структурное мышление,
— поймешь, насколько тебе подходит аналитика,
— получишь обратную связь на каждый шаг.
🔥 Это бесплатный шанс примерить новую профессию — вдруг это именно твое?
👉 Нажми, чтобы начать тест прямо сейчас
🔍 Пройди кейс-тест на реальной бизнес-задаче — всё, как в работе настоящего аналитика, но без необходимости иметь профильные навыки. Только мышление, логика и внимательность.
⚡️ Всего 10 конкретных вопросов — от постановки цели до финальных выводов. За 60 минут: — получишь реальные вводные от "коллег",
— прокачаешь структурное мышление,
— поймешь, насколько тебе подходит аналитика,
— получишь обратную связь на каждый шаг.
🔥 Это бесплатный шанс примерить новую профессию — вдруг это именно твое?
👉 Нажми, чтобы начать тест прямо сейчас
Что выведет этот код при запуске на Python 3.10+ (например, 3.11)?
📌 Подсказка:Подумайте о порядке проверок, о том, какие атрибуты попадают в others, и об использовании __match_args__.
Ответ:
Automatic mode
Mode manual, other keys: ['threshold', 'debug']
Low threshold 0
Краткое пояснение:
Для первого объекта (mode="auto", threshold=10) срабатывает первый case Config(mode="auto") → Automatic mode.
Для второго (mode="manual", threshold=5, debug=True) первый не совпадает, второй с threshold<5 не проходит (5 < 5 → False), зато третий case Config(mode=mode, **others) — биндинг mode='manual', остальные ключи (threshold и debug) попадают в others → Mode manual, other keys: ['threshold', 'debug'].
Для третьего (threshold=0) первый и третий не подходят (нет mode), а второй — case Config(threshold=threshold) if threshold<5 — срабатывает (0<5) → Low threshold 0.
@pythonl
📌 Подсказка:
Ответ:
Automatic mode
Mode manual, other keys: ['threshold', 'debug']
Low threshold 0
Краткое пояснение:
Для первого объекта (mode="auto", threshold=10) срабатывает первый case Config(mode="auto") → Automatic mode.
Для второго (mode="manual", threshold=5, debug=True) первый не совпадает, второй с threshold<5 не проходит (5 < 5 → False), зато третий case Config(mode=mode, **others) — биндинг mode='manual', остальные ключи (threshold и debug) попадают в others → Mode manual, other keys: ['threshold', 'debug'].
Для третьего (threshold=0) первый и третий не подходят (нет mode), а второй — case Config(threshold=threshold) if threshold<5 — срабатывает (0<5) → Low threshold 0.
@pythonl
Разработчик представил PyXL — уникальный аппаратный процессор, который исполняет Python-программы без использования традиционного интерпретатора или виртуальной машины.
Архитектура PyXL:
Python → CPython Bytecode → собственный набор инструкций для прямого исполнения на "железе".
Основан на стековой модели, полностью конвейерный, с сохранением динамической типизации Python без ограничений статических типов.
PyXL выполняет переключение GPIO с задержкой всего 480 наносекунд.
Для сравнения: MicroPython на Pyboard — 14–25 микросекунд, несмотря на более высокую частоту (168МГц против 100МГц у PyXL).
Разработчик самостоятельно создал:
Компилятор, линкер и генератор кода
Аппаратную реализацию процессора
Проект демонстрирует, что возможно аппаратное исполнение Python с высокой скоростью и без потери гибкости языка. Полные технические детали будут представлены на PyCon 2025.
🎬 Демо и подробности: https://runpyxl.com/gpio
@pythonl
Please open Telegram to view this post
VIEW IN TELEGRAM
На конференции LlamaCon CEO Microsoft Сатья Наделла объявил, что от 20 % до 30 % кода в репозиториях компании сегодня «написаны программным обеспечением», то есть с использованием искусственного интеллекта.
## Ключевые моменты
- Зависимость от языка. Лучшие результаты при генерации — на Python, более слабые — на C++.
- Интеграция на всех этапах. AI применяется не только для генерации чернового кода, но и для его ревью.
- Сравнение с конкурентами. Google уже сообщает о более 30 % AI-сгенерированного кода, Meta прогнозирует до 50 % при разработке своих языковых моделей.
- Долгосрочная перспектива. По прогнозам CTO Microsoft, к 2030 г. доля AI-генерируемого кода может вырасти до 95 %.
- Ограничения метрик. Пока не до конца ясно, что именно учитывается в «AI-коде» (автодополнение, шаблоны, бизнес-логика), поэтому цифры стоит воспринимать с осторожностью.
## Почему это важно
1. Ускорение разработки. Рутинные задачи автоматизируются, разработчики получают больше времени на архитектуру.
2. Новый уровень качества. Автоматическое ревью помогает быстрее находить ошибки, но требует строгой проверки.
3. Риски безопасности. Сгенерированный код нуждается в дополнительном анализе на уязвимости.
4. Эволюция ролей. Разработчики всё больше становятся архитекторами и аудиторами, а не «создателями» кода.
@pythonl
Please open Telegram to view this post
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
Это кроссплатформенный терминальный termux-ориентированный файловый менеджер, предназначенный для использования с проектом Uni-Curses
Запустите tuifi в терминале, или импортируйте его в один из ваших проектов Uni-Curses как компонент, например:
from TUIFIManager import *
Установка
sudo pip3 install tuifimanager --upgrade
pip3 install TUIFIManager --upgrade
https://github.com/GiorgosXou/TUIFIManager
@pythonl
Please open Telegram to view this post
VIEW IN TELEGRAM
def extend_list(val, lst=[]):
lst.append(val)
return lst
# Первый вызов: используем список по умолчанию
list1 = extend_list(10)
# Второй вызов: передаём новый пустой список
list2 = extend_list(123, [])
# Третий вызов: снова используем список по умолчанию
list3 = extend_list('a')
print('list1 =', list1)
print('list2 =', list2)
print('list3 =', list3)
🧩 Решение
В сигнатуре функции lst=[] создаётся один список при определении функции и затем переиспользуется во всех вызовах, где lst не передан.
Первый вызов
```python
list1 = extend_list(10)
lst не передан → берётся дефолтный список.
Добавляем 10.
⇒ list1 становится [10].
```p
Второй вызов
```python
list2 = extend_list(123, [])```
Передаём новый пустой список [].
В него добавляется 123.
⇒ list2 становится [123].
Третий вызов
```python
list3 = extend_list('a')```
Опять не передан
lst
Добавляем 'a'.
⇒ дефолтный список становится [10, 'a'], и list3 тоже ссылается на [10, 'a'].
Итоговый вывод программы:
```python
list1 = [10, 'a']
list2 = [123]
list3 = [10, 'a']```
Обратите внимание, что
list1 и list3
@pythonl
Please open Telegram to view this post
VIEW IN TELEGRAM
Главное:
🔍 Наследник Pyre
Pyrefly задуман как следующая версия проверяльщика типов Pyre от Meta, но с упором на скорость, модульную архитектуру и возможность генерации «типизированного» AST.
🚀 Реализовано на Rust
Большая часть кода написана на Rust для лучшей безопасности памяти и конкурентности. Только ~1 % кода в Python и ~6 % в TypeScript (для интерфейса сайта и LSP).
⚙️ Три этапа проверки
Сбор экспорта каждого модуля (решение всех import * рекурсивно)
Преобразование кода в набор «байндингов» (definitions, uses, anon) с учётом потоковых типов
Решение этих байндингов (flow-types, phi-функции при ветвлениях и рекурсии)
💡 Масштабируемость и инкрементальность
Модульно-ориентированный подход: проверка каждого модуля целиком, с возможностью параллельного запуска и минимальной сложности по сравнению с тонкозернистыми DAG-алгоритмами.
🛠️ Интеграция и упаковка
Разработчикам Rust: cargo build, cargo test
Во внутренних проектах Meta: запуск через Buck2 (buck2 run pyrefly -- check file.py)
Для PyPI: сборка колес через Maturin (pip install maturin && maturin build)
📡 IDE-функции и LSP
Включена поддержка Language Server Protocol для автодополнения, перехода к определению и интерактивной отладки в редакторах.
📆 Планы
Полная замена Pyre к концу 2025 года с выпуском стабильных версий на PyPI каждую неделю.
📜 Лицензия
MIT — свободное использование и вклад в проект приветствуются.
@pythonl
Please open Telegram to view this post
VIEW IN TELEGRAM
🚀 Jittor — фреймворк, использующий JIT-компиляцию и мета-операторы для оптимизации вычислений прямо во время выполнения.
Проект сочетает простоту Python-интерфейса с низкоуровневой компиляцией на C++/CUDA. В отличие от традиционных графовых подходов, он динамически компилирует операции под конкретную модель, что потенциально может ускорить выполнение сложных сетей.
🤖 GitHub
@pythonl
Проект сочетает простоту Python-интерфейса с низкоуровневой компиляцией на C++/CUDA. В отличие от традиционных графовых подходов, он динамически компилирует операции под конкретную модель, что потенциально может ускорить выполнение сложных сетей.
🤖 GitHub
@pythonl
✍️ novelWriter — минималистичный редактор для писателей с поддержкой Markdown. Проект использует облегченный синтаксис на основе Markdown и сохраняет все данные в виде обычных текстовых файлов, что делает его идеальным для работы с системами контроля версий.
Инструмент делает акцент на простоте и надежности. Вместо проприетарных форматов он использует чистый текст с метаданными в JSON. Редактор написан на Python с использованием Qt6 и доступен для всех основных ОС. При этом проект остается полностью открытым и принимает contributions, особенно в части переводов через Crowdin.
🤖 GitHub
@pythonl
Инструмент делает акцент на простоте и надежности. Вместо проприетарных форматов он использует чистый текст с метаданными в JSON. Редактор написан на Python с использованием Qt6 и доступен для всех основных ОС. При этом проект остается полностью открытым и принимает contributions, особенно в части переводов через Crowdin.
🤖 GitHub
@pythonl