Есть ли способ установить переменную экземпляра без вызова метода __set__ дескриптора?

Я создал собственный дескриптор, которому присвоил значение в своем классе. Однако я хотел бы сначала установить переменную экземпляра, не используя метод дескрипторов __set__.

class Descriptor:
    def __set_name__(self, owner, name):
        self.private_name = '_' + name

    def __get__(self, instance, owner=None):
        if instance is None:
            return self
        return getattr(instance, self.private_name)

    def __set__(self, instance, value):
        if value == 'bye':
            raise ValueError('blah')
        self.toggle(instance)
        setattr(instance, self.private_name, value)
   
    @staticmethod
    def toggle(instance):
        pass

class Foo:
    bar = Descriptor()

    def __init__(self, bar):
        # no need to call descriptor initially for some reason ok? but is still called (unnecessary)
        self.bar = bar

foo = Foo('hi')
foo.bar = 'bye'  # descriptor needed here and with every subsequent change to bar.

Есть ли способ обойти это и установить self.bar напрямую?
У меня возник этот вопрос, поскольку изначально я использовал дескриптор @property, который при использовании позволял вызывать как метод дескриптора, так и частную переменную, а это было именно то, что мне нужно. Поскольку @property является дескриптором, должен быть разумный способ сделать это (хотя причина, по которой это работает с @property, заключается в том, что частная переменная определена в пределах моего класса, а не класса дескриптора, как это делается с пользовательскими дескрипторами, что позволяет оба должны быть изменены внутри класса, но только общедоступная версия вне области действия класса (я знаю, что частные переменные не являются действительно частными, но это не имеет значения).) Например, тот же код с использованием @property:

class Foo:
    def __init__(self, bar):
        # no need to call setter initially
        self._bar = bar

    @property
    def bar(self):
        return self._bar

    @bar.setter
    def bar(self, value):
        self._bar = value

foo = Foo('hi')
foo.bar = 'bye'  # property setter called.

Однако в этом случае геттеры и сеттеры занимают гораздо больше места, когда вводится больше переменных экземпляра, и метод toggle из исходного декоратора приходится переписывать для каждого нового добавленного сеттера (именно это заставило меня переписать @properties как собственный класс дескриптора, поскольку он казался местом, где можно использовать oop, чтобы не повторяться).

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
62
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ничто из того, о чем вы думали, на самом деле не имеет значения. Ваш property устанавливает self._bar, и вы обходите его, устанавливая self._bar напрямую. Ваш пользовательский дескриптор делает то же самое, только через setattr, поэтому вы все равно обходите его, устанавливая атрибут _bar экземпляра напрямую:

class Foo
    bar = Descriptor()
    def __init__(self, bar):
        self._bar = bar

омг, спасибо за этот ответ, кажется, вся эта проблема была вызвана тем, что pycharm был глупым и жаловался, что «Неразрешенная ссылка на атрибут «_bar» для класса «Foo», и я не удосужился запустить и проверить, действительно ли это правда. мне на самом деле надоело pycharm... :/ Думал удалить этот вопрос, но кто-то может в конечном итоге сделать те же предположения, что и я, и начать искать решение проблемы, которой не существует...

r5ne 28.08.2024 19:30

Обновление до последней версии pycharm исправило это, кстати, это моя вина.

r5ne 28.08.2024 20:09

Другие вопросы по теме