Есть ли способ установить переменную экземпляра без вызова метода __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 можно создавать кросс-платформенные приложения для Windows, macOS и Linux.


62
1

Ответ:

Решено

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

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