Pull to refresh
40
Karma
0
Rating
Tishka17 @Tishka17

Пользователь

  • Followers 49
  • Following 6

«Оптимизируем» функции на уровне AST

Было бы интересно посмотреть на реализацию оптимизации байткода. Есть примеры?

Переписать на другие языки - очевидный и хороший вариант, но почему бы не арссмотреть альтернативы?

«Оптимизируем» функции на уровне AST

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

Алгебраические типы данных и Python

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

Будущее аннотаций типов в Python

Поправьте, если я не прав, но PEP 563 работает начиная с Python3.7, который вышел больше 4 лет назад (надо было только написать from __future__ import annotations). У меня есть проект, решающий похожие на pydantic задачи и в нем не было проблем связанных с этим PEP. Есть подозрение, что проблемы Pyndatic связаны не с питоном, а c принятыми ими неверными решениями.

Аннотации типов можно использовать для двух вещей, связанных с классами, хранящими данные. Во-первых, это валидация кода - что переданные данные соответствуют задекларированным типам полей (проверка типов). Во-вторых, это преобразование примитивных структур данных с датакласс (парсинг). Первая задача решается статическими анализаторами, такими как mypy или pyright. Вторая задача в общем случае должна решаться отдельным слоем кода (вспоминаем single responsibility, разделение DTO и view-слоя и т.п.).

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

Подумываете об использовании MongoDB?

Пишут что в 8й версии в части случаев можно без этого. Но я не DBA, только что сам нагуглил

https://mysqlserverteam.com/mysql-8-0-innodb-now-supports-instant-add-column/

Подумываете об использовании MongoDB?

база не обрастает пустыми полями

а какая разница? ну кроме того, что не видно какие поля могут встретиться

удаляют поля

это требует миграции, если действительно надо удалить, а не игнорировать в выборках

Ещё кейсы изменения требований:

  • разделить поле на два (с вычислением значения для старых записей)

  • разделить сущность на две с разным жизненным циклом

  • вместо плоского массива строк хранить массив объектов

  • для вложенных объектов ввести единый реестр метаинформации с централизованным редактированием (или наоборот убрать)

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

Подумываете об использовании MongoDB?

Но погодите, если меняются требования - это не просто добавление полей. Это зачастую изменение связей, необходимости уникальности, наличия каких-то значений. Если у вас каждый день добавляется новое nullable поле - это фигня и не требует вообще никаких усилий при написании миграций и в реляицонной БД (а иногда такие поля можно просто сунуть в связанную таблицу key-value-parent_id). А вот когда у вас вместо отношения один-ко-многим стало многие-ко-многим - что делать?

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

Подумываете об использовании MongoDB?

Ну то есть схема все таки есть? Но не в БД

Подумываете об использовании MongoDB?

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

Подумываете об использовании MongoDB?

Подскажите, а что будет когда продукт вырастет? Как вы поддерживаете код в согласованном состоянии, когда схема меняется "чуть ли не каждый день"? Не приводит ли это к тому, что проект сразу же становится легаси? Если нет, то за счет чего?

Подумываете об использовании MongoDB?

Именно. Монга не имеет некоторых механик таких каких как принудительная декларация схемы или контроль целостности Foreign key. Это приводит к повышенным требованиям к гигиене кода. И соответственно у нерадивых разработчиков больше возможностей накосячить

Подумываете об использовании MongoDB?

Решается очень легко: вы должны где-то записать, что какие-то поля могут отсутствовать. Это и есть схема. Просто она теперь не в БД, а на уровне приложения. Если в каком-нибудь postgres у вас будет написано `date_of_birth DATETIME NULL`, то теперь это будет написано в документации, в коде, в тестах или ещё где-то.

Пишем обёртку над SQLAlchemy Сore

Удаление коннекта из модели — не более чем стиль, это не влияет на логику. Вам нужна механика превращения запроса в понятный коннектору — он у вас есть. И, вам нужен движок, который это умеет вызывать. Если подумать, получается, что я описываю async session алхимии: await session.execute(query). В этом случае вы можете разделить логику подготовки запросов и их выполнения. Или подготовить запрос один раз и переиспользовлать в разных местах.


Что касается databases — я не очень тесно с ним работал. Кажется, там были непонятки с жизненным циклом соединений. Плюс я категорически против подхода "автокоммит": найти потерянный коммит намного проще чем потерянную транзакцию. В этом плане мне нравится подход алхимии. Плюс databases раньше не умели relationship (не знаю, как сейчас).


В целом я бы посоветовал не пытаться сократить простые и очевидные места, которые при этом и так не слишком длинные.

Пишем обёртку над SQLAlchemy Сore

Я не имею ничего против статьи. Как образовательный материал — это очень хорошо. Но тянуть такое в прод я бы не стал. Возможно дело в моём травматическом опыте выпиливания "обертки" на алхимией.


В данном случае совершенно непонятно чем User.select() лучше чем select(User). Первое — ваше изобретение, второе — стандартный синтаксис. Очевидно, что новые члены команды будут порываться использовать второе. Я понимаю, что многие вещи вы реализовали, но в алхимии очень много полезных возможностей и в конце концов вам придется реализовать их все. Например, я не вижу having, не уверен насколько оно корректно работает с hybrid_property, alias или внешними ключами, ссылающимися на ту же таблицу (возможно проблемы нету, я не проводил эксперименты).


Так же не понятно, зачем ограничиваться core, когда вы и так используете declarative_base. Если речь идет о сокращении кода — как вы будете решать проблему N+1? Алхимия представляет механизм опций для загрузки relstionship. Это намного удобнее, чем руками писать джойны и подзапросы.


Есть подозрение, что материал немного устарел, сейчас в sqlalchemy идет работа по снижению отличий crore и orm. В частности рекомендую к ознакомлению Migrating to SQLAlchemy 2.0. В новом синтаксисе вы сначала подготавливаете запросы а потом выполняете их в сессии. При чем async и sync версия отличается только этапом выполнения запроса (фактически await словом в одном вызове). В связи с этим мне кажется, изобретение своего конструктора запросов поверх стандартного не актуальным.


Собственно что в бете? Работа самого async session. Конструкторы запросов и прочие механики работают в синхронной версии точно так же.

Пишем обёртку над SQLAlchemy Сore

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

С точки зрения разделения зон ответственности, модель должна отвечать только за свои данные: данные экземпляра и как эти данные хранятся в бд. Например, сюда хорошо ложатся гибридные свойства и relationship. Если у вас регулярно фигурируют сложные выборки или агрегации, их можно оформить как отдельные модели (алхимия позволяет указать не имя таблицы, а запрос). За счёт этого мы в дальнейшем можем переиспользовать логику моделей в совершенно разных выборках или даже без непосредственно запросов БД.

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

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

Пишем обёртку над SQLAlchemy Сore

А свою объектку менее рискованно?

Протоколы в Python: утиная типизация по-новому

Я бы скорее обратился к интерфейсам как они определены у Банды Четырех. Протоколы как раз им полностью соответствуют.

Строгая десериализация YAML в Python c библиотекой marshmallow

Не нужно использовать ForwardRef в качестве аннотации. Просто указывайте тип в кавычках и все будет работать автоматом.


Так же я бы советовал не вкладывать классы внутрь классов без особой нужды, диктуемой некоторыми фреймворками.


Пользуясь случаем, так же хочу предложить свою библиотеку для парсинга датаклассов: dataclass-factory. При её использовании не требуется менять иерархию классов (как в случае c pydantic или mashumaro), но при необходимости все ещё можно гибко настраивать поведение парсинга с помощью опциональных "схем".


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


from dataclasses import dataclass
from enum import Enum
from typing import Optional

from dataclass_factory import Factory
from yaml import load, SafeLoader

class Color(Enum):
    RED = "red"
    GREEN = "green"
    BLUE = "blue"

@dataclass
class BattleStationConfig:
    processor: "Processor"  # вместо `ForwardRef`
    memory_gb: int
    led_color: Optional[Color] = None

@dataclass
class Processor:
    core_count: int
    manufacturer: str

yaml = """
processor:
  core_count: 8
  manufacturer: Intel
memory_gb: 8
led_color: red
"""

factory = Factory()  # здесь задаются дополнительные настройки обработки

loaded = load(yaml, Loader=SafeLoader)
print(factory.load(loaded, BattleStationConfig))  
# BattleStationConfig(processor=Processor(core_count=8, manufacturer='Intel'), memory_gb=8, led_color=<Color.RED: 'red'>)

Многопоточное скачивание файлов с ftp python-скриптом

  1. ВСЕ bмпорты переместить наверх соответствующих файлов
  2. Логирование настраивать в main один раз. Код, который выполняет основную работу не должен знать куда там пишутся логи, он просто использует один раз созданный для него logger (один из немногих случаев, когда можно сделать глобальную переменную)
  3. Выкинуть MyLogger, разобраться с иерархией логгеров, хэндлерами и прочим, что уже есть в logging
  4. Вероятно выкинуть self.ftp.__class__.encoding = sys.getfilesystemencoding(). Это оооочень подозрительный код. Может сломать работу другого кода, использующего ftp библиотеку
  5. Убрать наследование от Thread. Это нужно бывает когда вы делаете свою логику многозадачности (таймеры, универсальные воркеры). Бизнес логику в треде запускают через задание target
  6. Выкинуть global. Константы и так прекрасно ищутся в глобальном скоупе.
  7. Конфиг грузит из конфигурационного файла или переменных окружения. Когда вы упакуете программу как положено, пользователь не сможет править её код, он будет просто её устанавливать.
  8. Для ограничения числа одновременных закачек воспользоваться ThreadPoolExecutor

В общем, 90% кода показывать другим людям не стоит.

Обширный обзор собеседований по Python. Советы и подсказки

Предпочитаю избегать паттерна синглтон, но раз вы упомянули его — расскажите, пожалуйста, а какие реально проблемы синглтона через декоратор для тестирования? И почему самое лучшее — через метакласс, а не тупо глобальная переменная в экзепмляром в модуле?

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity