Объединение @dataclass и @property

Я хотел бы использовать @dataclass для удаления большого количества шаблонов, но мне также нравится инкапсуляция данных, предлагаемая @property. Могу ли я делать и то, и другое одновременно?

В качестве примера игрушки у меня есть такой класс, как

class Breakfast:

    def __init__(self, sausage: str, eggs: str = "Scrambled", coffee: bool = False):
        self._sausage = sausage
        self._eggs = eggs
        self._coffee = coffee

    @property
    def sausage(self):
        return self._sausage

    @property
    def eggs(self):
        return self._eggs

    @property
    def coffee(self):
        return self._coffee

    def __repr__(self):
        ...

    def __eq__(self):
        ...

где у меня также могут быть сеттеры для некоторых свойств. Я бы хотел написать это в такой форме

@dataclass(property=True)
class DataBreakfast:
    sausage: str
    eggs: str = "Scrambled"
    coffee: bool = False

(где, конечно, мой аргумент декоратора не работает), который будет выполнять все рутинные вещи, которые делает @dataclass, и по существу выводит код первого фрагмента. Затем я мог бы вручную добавить сеттеры в остальную часть тела на досуге.

Это кажется достаточно распространенным вариантом использования, но я не мог придумать, как заставить его работать. Замороженный параметр - самый близкий к тому, что я хочу, но на самом деле он не ведет себя как @property, поскольку он исключает какой-либо установщик.


person ScienceSnake    schedule 15.05.2021    source источник
comment
Что вы имеете в виду под инкапсуляцией данных? вы хотите, чтобы атрибуты по умолчанию были доступны только для чтения?   -  person Arne    schedule 16.05.2021
comment
@ Арн, как минимум, да. Но также оставляю себе возможность делать что-то еще (например, увеличивать счетчик) каждый раз, когда осуществляется доступ к атрибуту или его изменение.   -  person ScienceSnake    schedule 16.05.2021
comment
Я не могу найти способ написать решение, которое сокращает объем работы для вашего варианта использования. Если все, что вам нужно, по умолчанию доступно только для чтения, есть frozen или, если вы хотите, чтобы это было только в некоторых полях, _2 _. Если вы хотите пропустить запись @property и иногда хотите добавить геттер, вам не повезло, потому что вы получите ошибку типа во время синтаксического анализа тела класса, даже до того, как декоратор класса данных получит применить свою логику. И если вы хотите добавить логику, такую ​​как счетчик доступа, вам все равно придется написать свойство.   -  person Arne    schedule 17.05.2021
comment
Единственное, что я могу заставить работать разумно, - это использовать свойства под капотом, но без какого-либо специального кода внутри. и если вы попытаетесь с этим повозиться, например, задним числом добавить геттер, все сломается, что вообще не кажется полезным.   -  person Arne    schedule 17.05.2021
comment
Хорошо, спасибо за ответ. Думаю, я буду проще и просто не буду использовать @dataclass тогда, а просто продолжу делать свои @property вручную. Должен признаться, я немного удивлен, что это почти невозможное, я мог подумать, что то, чего я хотел, действительно было бы очень распространенным явлением.   -  person ScienceSnake    schedule 17.05.2021
comment
На всякий случай, если вы еще не наткнулись на это, - это сообщение в блоге об использовании классов данных со свойствами. Использование класса данных не уменьшает объем работы, но вы все равно получаете все остальные вещи, такие как __repr__, бесплатно.   -  person Arne    schedule 17.05.2021
comment
@ScienceSnake: Каким будет эффект или значение @dataclass(property=True)?   -  person martineau    schedule 18.05.2021
comment
@martineau По сути, это превратит второй фрагмент кода в вопросе в первый. Другими словами, каждое поле foo, определенное в классе обычным @dataclass способом, станет атрибутом _foo и будет добавлен метод @property def foo(self): return self._foo. Это также можно сделать в Field отдельно. Пользователь может свободно определять вручную любой @foo.setter по своему усмотрению (если, возможно, не используется тег frozen). В этом есть смысл? Я не эксперт, но мне это не кажется особенно невыполнимым.   -  person ScienceSnake    schedule 18.05.2021
comment
Я думаю, что можно было бы иметь свойства с геттерами, определяемыми автоматически, но я не уверен, разрешить ли необязательные сеттеры определяться в теле (если я правильно понимаю ваш ответ).   -  person martineau    schedule 18.05.2021
comment
Извините, я имел в виду необязательные сеттеры, поскольку пользователь просто записывает свои собственные методы в тело класса, помимо того, что делает @dataclass. Ничего не происходит автоматически, и для этого нет дополнительных необязательных параметров для поля. Я взглянул на исходный код классов данных, но это выходит за рамки моей способности переваривать, не говоря уже о том, чтобы пытаться изменить.   -  person ScienceSnake    schedule 18.05.2021
comment
Это то, что я имел в виду, когда речь шла об установщиках параметров - и это та часть, которую я не уверен, что это возможно (остальное , я полагаю).   -  person martineau    schedule 18.05.2021
comment
Ха, я бы подумал, что это было бы проще всего, просто позволив пользователю переопределить какое-то поведение по умолчанию. Я явно не в своей тарелке. Должен ли я поднять это где-то как запрос функции, или это слишком нишевое и никогда не произойдет, если я не сделаю это сам?   -  person ScienceSnake    schedule 18.05.2021