Я создал собственный дескриптор, которому присвоил значение в своем классе. Однако я хотел бы сначала установить переменную экземпляра, не используя метод дескрипторов __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, чтобы не повторяться).
Ничто из того, о чем вы думали, на самом деле не имеет значения. Ваш property
устанавливает self._bar
, и вы обходите его, устанавливая self._bar
напрямую. Ваш пользовательский дескриптор делает то же самое, только через setattr
, поэтому вы все равно обходите его, устанавливая атрибут _bar
экземпляра напрямую:
class Foo
bar = Descriptor()
def __init__(self, bar):
self._bar = bar
Обновление до последней версии pycharm исправило это, кстати, это моя вина.
омг, спасибо за этот ответ, кажется, вся эта проблема была вызвана тем, что pycharm был глупым и жаловался, что «Неразрешенная ссылка на атрибут «_bar» для класса «Foo», и я не удосужился запустить и проверить, действительно ли это правда. мне на самом деле надоело pycharm... :/ Думал удалить этот вопрос, но кто-то может в конечном итоге сделать те же предположения, что и я, и начать искать решение проблемы, которой не существует...