Проблемы с созданием постоянного класса дескриптора для Python

>>> class Const(object):        # an overriding descriptor, see later
...     def __init__(self, value):
...         self.value = value
...     def __set__(self, value):
...         self.value = value
...     def __get__(self, *_):  # always return the constant value
...         return self.value
... 
>>> 
>>> class X(object):
...     c = Const(23)
... 
>>> x=X()
>>> print(x.c)  # prints: 23
23
>>> x.c = 42
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __set__() takes 2 positional arguments but 3 were given

Что значит

TypeError: __set__() принимает 2 позиционных аргумента, но было задано 3`

означает?

Является ли __set__() методом, принадлежащим типу дескриптора Const?

Какая подпись у __set__()?

Спасибо.


person Tim    schedule 29.06.2017    source источник
comment
Предлагается к повторному открытию. Это лишь частичное совпадение с stackoverflow.com/questions/3798835 (т. е. та же категория темы, но не фактический вопрос, обстоятельства, или особенности). В частности, этот вопрос касается инструмента для создания констант (который является новым) и сосредоточен на методе _set_ (который является новым), а также как конкретная проблема TypeError за неверную подпись (тоже новую).   -  person Raymond Hettinger    schedule 29.06.2017
comment
@RaymondHettinger: дубликат отвечает на вопрос, почему появился TypeError, предоставляя правильную подпись. Это был весь первоначальный вопрос; он не спрашивал о цели Const. (Дубликат еще больше подходит, если принять во внимание комментарий ОП.)   -  person Ry-♦    schedule 30.06.2017
comment
@Ryan Похоже, у вас другое представление о точной копии, и теперь вы потеряли интересный вариант. Кроме того, кажется оскорбительным закрыть второй раз. Это должно было быть предоставлено другим решать, соглашаться или нет, а не принимать диктаторское решение, перевешивающее понимание главного участника в категории. По вашим рассуждениям КАЖДЫЙ вопрос об дескрипторах будет помечен как дубликат вопроса о расплывчатом понимании дескрипторов.   -  person Raymond Hettinger    schedule 30.06.2017
comment
@RaymondHettinger: Это не интересный вариант. Это отсутствие фундаментальных исследований. Также обратите внимание, что причина закрытия больше не «точная копия», а «на этот вопрос уже есть ответ здесь»; это было преднамеренное изменение, требуемое именно для такой ситуации.   -  person Ry-♦    schedule 30.06.2017
comment
@Ryan Ничто в других ответах не касается создания класса Const(). Кроме того, вы первый комментарий о том, что любой из первых 10 результатов Google ... не соответствует стандартам StackOverflow и указывает на то, что на самом деле вы не понимаете стоящую перед ОП задачу.   -  person Raymond Hettinger    schedule 30.06.2017
comment
@RaymondHettinger: Верно, но вопрос был не в этом. Вопрос был «почему я получаю эту ошибку TypeError?». Ответ заключается в том, что подпись была неправильной, а подпись находится в связанном вопросе. Если ОП хочет отредактировать свой вопрос, чтобы задать что-то более тонкое, отлично — это именно то, для чего нужны удержания.   -  person Ry-♦    schedule 30.06.2017
comment
Кроме того, отсутствие оригинального исследовательского комментария является натяжкой, учитывая, что ОП опубликовал код и попытался решить исходную проблему. И теперь вы заминусовали мой ответ не потому, что он был неправильным, а потому, что вы злитесь и хотите наброситься. ИМО, ваше поведение не соответствует стандартам StackOverflow и должно быть отмечено модератором.   -  person Raymond Hettinger    schedule 30.06.2017


Ответы (1)


Подпись для __set__

Подпись для __set__ задокументирована здесь:

object.__set__(self, instance, value) Вызывается, чтобы установить для атрибута экземпляра экземпляра класса-владельца новое значение value.

Значение ошибки типа

Ошибка TypeError говорит вам, что параметр instance отсутствует, он должен быть def __set__(self, instance, value): ....

Проработанное решение

Вот один из способов заставить класс Constant работать правильно:

class Const(object):
    def __init__(self, value):
        self._value = value
    def __set__(self, inst, value):
        raise TypeError('Cannot assign to a constant')
    def __get__(self, inst, cls=None):
        return self._value

class X(object):
    c = Const(23)

Попробовав его в интерактивном сеансе, вы получите:

>>> x = X()
>>> print(x.c)
23
>>> x.c = 42
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    x.c = 42
  File "/Users/raymond/Documents/try_forth/tmp.py", line 5, in __set__
    raise TypeError('Cannot assign to a constant')
TypeError: Cannot assign to a constant
person Raymond Hettinger    schedule 29.06.2017
comment
Спасибо! (1) В чем разница между двумя параметрами self и instance из object.__set__? Ссылаются ли они оба на один и тот же экземпляр класса (если да, то зачем нам два параметра для одного и того же аргумента)? (2) Аналогично, в object.__get__(self, instance, owner) какие различия между двумя параметрами self и instance? Относится ли owner к классу (если да, то зачем нам нужен параметр для класса, учитывая, что мы можем ссылаться на класс, не передавая его в качестве аргумента)? - person Tim; 29.06.2017
comment
self является экземпляром Const, а inst — экземпляром класса X. - person Raymond Hettinger; 29.06.2017