Search
Write a publication
Pull to refresh
0
0
Send message

В хранилищах пар ключ-значение аннотируйте словари как мэппинги

этот совет выглядит скорее вредным, потому что typing `dict[str, str]` буквально и описывает hashmap неопределенной длины, но однородного содержания.

Подводные камни прячутся в гибкости. Мы можем описать коллекцию книг как:

all_books: list[Book] = []

А можем как хэшмапу с быстрым доступом по выбранному свойству:

books_from_names: dict[str, Book] = {book.name: book for book in all_books}

Но гибкость нам позволяет и сам Book описать как словарь:

dict_book = {
  "name": "Azbuka",
  "pages": 33,
  "weight": 444.4,
  "category": Category.HORROR,
}

Тем не менее легко выделить критерии, по которым легко признать, что у вас на руках Object:

  • Значения, вероятно, неоднородны (хотя легко придумать описание книги, подходящее под `dict[str, str]`)

  • Ключи - это не свойство значения, доступного по ключу, это свойство Object.

  • Длина словаря определена набором свойств описываемого Object

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

И такое можно делать - но желательно осознанно. Иначе по коду могут начать летать словари словарей, примерно с таким тайпингом:

dict[str | int, dict[str, dict | str] | float | str | int]

В качестве же компенсации за критику присоединюсь к рекомендации причинять pydantic. Начиная с V2 он вырос на голову относительно себя:

  • Написан на rust (В смысле, прибавил в производительности)

  • Через Annotated можно делать крутяцкие валидации-сериализации и переиспользовать их

  • Дженерики начали работать как дженерики (в отличие от батьки-питона) - в том числе и с предыдущим пунктом.

  • Умеет включать в свои модели данных датаклассы и восстанавливать их при парсинге json

  • Имеет TypeAdapter, который позволить спарсить из json в том числе чистый dataclass, такое вот содружество.

  • Наверняка я что-то ещё интересного упустил, но и так вроде неплохо звучит.

у нас тут поднято уже два разных вопроса:

comprehansion как синтаксический сахар

Генератор отдельно для наглядности сахара вынесен, конечно же. Это тоже валидный код:

comp_1 = [i for i in range(10)]
comp_2 = list(i for i in range(10))
assert comp_1 == comp_2

Почему включения быстрее циклов?

И то что лежит на поверхности (т.е. для этого даже не нужно смотреть байткод) - это изменение объектов (в данном случае изменяем экземпляр списка) и их особенности по работе с памятью:

from sys import getsizeof

result = []
size_ = getsizeof(result)
for i in range(10000):
    result.append(i)
    if (new_size := getsizeof(result)) > size_:
        size_ = new_size
        print(i, size_)

где вывод будет:

0 88
4 120
8 184
16 248
24 312
32 376
40 472
52 568
64 664
76 792
92 920
108 1080
128 1240
148 1432
172 1656
200 1912
232 2200
...

Итого, чем больше мы добавляем объектов в коллекцию, тем больше питон тратит времени на работу с памятью. Направления для изучения:

  • Как вообще питон обращается с памятью.

  • Различия по работе с памятью по встроенных типах коллекций

  • Вопрос в заголовке на просторах stackoverflow

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

Почему включения быстрее циклов?

Потому что не изменяет размер существующих объектов, в отличие от.

comprehansion - это синтаксичеcкий сахар вокруг генератора:

comp_1 = [i for i in range(10)]
comp_2_gen = (i for i in range(10))
comp_2 = list(comp_2_gen)
assert comp_1 == comp_2

Information

Rating
Does not participate
Registered
Activity