Pull to refresh

Comments 35

С тех пор, как я познакомился с pandas, я всё чаще использую его в тех ситуациях, в которых раньше взял бы список из namedtuple.
Справедливости ради, есть либа dataslots или же крутой attrs. Но реализация dataclass в 3.7 безумно ущербная, к сожалению :(
Ну, помимо того, что там нет возможности таки включить слоты, что как бы очень нелогично, там так же нет никакой валидации по типам, возможности расширения или каких-то полезных твиков.

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

Ну и сама реализация в духе «а давайте понапихаем методов в класс» не очень красивая, на мой взгляд. Мне бы куда больше понравилась реализация через мета-классы, опять же, потому что она расширяема.

Мне кажется, сами авторы довольны дизайном дата-классов. Вот выступление Реймонда Хеттингера по этому поводу. Про слоты он там тоже говорит — мол, жаль, что не получилось, в будущем, возможно, поддержим.

Ну, я безусловно рад за авторов, но это же программирование, тут не бывает правильных ответов или реализаций, что бы всем понравились :)

Авторы ставили перед датаклассами одни цели, я себе нафантазировал другие и вот получилось то, что получилось :)
На мой взгляд, датаклассы — полезная штука :)
А валидацию можно и прикрутить.
Вот именно. Я тоже очень ждал датаклассов, а когда глаза побежали по этому бзацу в топике:
Когда впервые видишь дата-класс, хочется перейти на новую версию языка только ради него:

У меня промелькнула сперва мысль, что «да!, дейтсвительно хочется перейти на другую сторону улицы!»
Потом был когнитивный диссонанс. Датаклассы получились совсем не тем. Хотелось, ытобы на них можно было делать полноценный ORM, хотелось больше свободы управления типами, больше средств автоматизации для валидации, конвертации и сериализации. Получилось же, что теперь это всёё равно приходится впиливать вручную, но появляется еще одна «магическая» скрытая прослойка в виде декоратора, который «колдует» над моим классом.

В моём представлении главная проблема с namedtuples в отсутствии синтаксического сахара работы с словарями.


Если бы мы вместо foo["bar"] могли бы писать foo.bar, наша жизнь была бы восхитительной, и namedtuples не понадобились бы. Ансибл, например, так разрешил в шаблонах, и оно восхитительно.

Да. Но в самом языке было бы лучше.
ну есть же Lua :)

foo = {bar = 42}
print(foo[«bar»], foo.bar)

Но lua не питон. Обидно.
Как раз наоборот, это просто замечательно, что lua не питон. :)

class Bunch(dict):
def init(self, *args, *kwargs):
super().init(
args, **kwargs)
self.dict = self

Затупил с форматированием, но идея должна быть понятна :)

Это есть на стековерфлоу, и там же приведены минусы такого подхода:
  • входящие данные могут запороть служебные свойства и методы, например keys() или dunder'ы.
  • на некоторых версиях питона дёт утечку памяти
  • ну и просто крайне неочевидно.

Так что, если нужен attrdict, лучше написать явную логику фильтрации ключей и хранить всё в отдельном словаре.
Для удобства конструирования namedtuple можно переопределить магический метод __new__().
Примерно так
class Pet(namedtuple('BasePet', ('type', 'name', 'age'))):
    @staticmethod
    def __new__(cls, type, name='', age=1): #можно делать необязательные параметры
        #тут можно делать преобразование типов или иную логику
        type = str(type)
        name = name if name else default_names.get(type, type)
        return super(Pet, cls).__new__(cls, name, type, age)

Забыл одну строчку:
__slots__ = ()

Она нужна, чтобы указать, что мы используем механизм slots и в классе-потомке. В этом случае родительские slots мы унаследуем, а своих добавим ноль (пустой кортеж).
UFO just landed and posted this here
Это логичное предположение, если знаешь про слоты. В докладе, на который я выше дал ссылку, Реймонд Хеттингер говорит, что просто не получилось их заиспользовать — а то бы так и сделали.
UFO just landed and posted this here
Так происходит, потому что обычные объекты в питоне таскают с собой увесистый дандер __dict__

Если вы давно работаете с питоном, то наверняка знаете: легковесный объект можно создать через дандер __slots__:

Прошу простить мое невежество, но что за термин "дандер"?
Гугл (при попытке поиска) отсылает к домашнему самогоноварению :)

«Дандер» — калька с английского dunder = Double UNDERscore. Они же «магические методы» вида __whatever__

UFO just landed and posted this here
кортеж согласно Википедии

Почему вы считаете кортежи изобретением питона, при том что это математический термин, широко применявшийся в информатике например при описании реляционых баз данных, когда питона насколько я помню, еще не существовало? Возможно питон и был первым языком, где такое появилось, но тут уже мало кто может быть уверенным. Но базы данных точно были раньше, статьи Кодда датируются где-то 1970 годом.
Возможно питон и был первым языком, где такое появилось, но тут уже мало кто может быть уверенным.
Не был. В детстве я читал про язык РАПИРА.
Я в том смысле, что вряд ли мы найдем самый первый.
вряд ли мы найдем самый первый.
Раньше LISP'а не так много языков было, но утверждать, что это он, не буду. ¯\_(ツ)_/¯
Я тоже. Но по-моему в самом первом лиспе (а это где-то 1960) были только car/cdr, а это все-таки не кортежи ну никак). Впрочем, я практически познакомился с лиспом вообще где-то в 1990-х, на AutoCAD, так что в истории его могу плавать.
Ещё есть отличный способ — наследование от
typing.NamedTuple
. Работает так же, выглядит прилично.


class A(typing.NamedTuple):
    field: int
    field_with_default: int = 3

Так, стоп… а нафига нам после этого классические namedtuple и dataclasses вместе взятые? Ну ок, кроме специфических случаев обработки CSV.
Я даже задумался выкинуть пакет `dataclasses` из проекта на 3.6 питоне и полностью юзать именно этот вариант…

В 95% случаев, имхо, dataclasses не нужны. Только если нужны мутабельные контейнеры — их на NamedTuple не сделаешь. Плюс, в typing.NamedTuple нельзя переопределять некоторые методы, а точнее:


# attributes prohibited to set in NamedTuple class syntax
_prohibited = ('__new__', '__init__', '__slots__', '__getnewargs__',
               '_fields', '_field_defaults', '_field_types',
               '_make', '_replace', '_asdict', '_source')
Sign up to leave a comment.

Articles