-2
>>> 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

What does

TypeError: __set__() takes 2 positional arguments but 3 were given`

means?

Is __set__() a method belonging to the descriptor type Const?

What is __set__()'s signature?

Thanks.

Raymond Hettinger
  • 216,523
  • 63
  • 388
  • 485
Tim
  • 1
  • 141
  • 372
  • 590
  • Suggested for re-opening. This is only a partial overlap with https://stackoverflow.com/questions/3798835/ (i.e. same topic category but not the actual question, circumstances, or specifics). In particular, this question is asking about a tool for making constants (that is new) and is focused on the \__set__ method (that is new), and as the specific problem of a *TypeError* for an incorrect signature (that is new as well). – Raymond Hettinger Jun 29 '17 at 07:38
  • @RaymondHettinger: The duplicate answers the question of why the `TypeError` appeared by providing the correct signature. That was the entire original question; it didn’t ask about the purpose of `Const`. (The duplicate is even more suited when taking the OP’s comment into account.) – Ry- Jun 30 '17 at 04:54
  • @Ryan You seem to have a different notion of "exact duplicate" and have now caused an interesting variant to have been lost. Also, it seems abusive to have closed a second time. That should have been left to others to decide whether to agree or not rather than making a dictatorial decision overriding insight of a top contributor in the category. By your reasoning, EVERY question about descriptors would be marked as duplicate of the vague "understanding descriptors" question. – Raymond Hettinger Jun 30 '17 at 05:01
  • @RaymondHettinger: It’s not an interesting variant. It’s a lack of basic research. Also note that the close reason is no longer “exact duplicate” but “this question already has an answer here”; this was an intentional change exacted precisely for this sort of situation. – Ry- Jun 30 '17 at 05:04
  • @Ryan Nothing in the other answers covers making a Const() class. Also, you're first comment about "Any of the first 10 Google results..." is not up to StackOverflow standards and indicates not really understanding the OP's task at hand. – Raymond Hettinger Jun 30 '17 at 05:11
  • @RaymondHettinger: Right, but that wasn’t the question. The question was “why am I getting this TypeError?”. The answer is that the signature was wrong, and the signature is in the linked question. If the OP wants to edit their question into asking something more nuanced, great – that’s exactly what holds are for. – Ry- Jun 30 '17 at 05:12
  • Also the "lack of original research" comment is a stretch given that the OP posted a code and made an attempt at a solution for an original problem. And now, you've downvoted my answer not because it was incorrect but because you're mad and want to lash out. IMO, you're behavior is not up to StackOverflow standards and should be flagged to a moderator. – Raymond Hettinger Jun 30 '17 at 05:17

1 Answers1

1

Signature for __set__

The signature for __set__ is documented here:

object.__set__(self, instance, value) Called to set the attribute on an instance instance of the owner class to a new value, value.

Meaning of the TypeError

The TypeError is tell you that the instance parameter is missing, it should be def __set__(self, instance, value): ....

Worked-out solution

Here's one approach to making the Constant class work correctly:

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)

Trying it out in an interactive session gives:

>>> 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
Raymond Hettinger
  • 216,523
  • 63
  • 388
  • 485
  • Thanks! (1) What differences are between the two parameters `self` and `instance` of `object.__set__`? Do they both refer to the same instance of the class (if yes, why do we need two parameters for the same argument) ? (2) In `object.__get__(self, instance, owner)`, similarly, what differences are between the two parameters `self` and `instance` ? Does `owner` refer to the class (if yes, why do we need a parameter for the class, given that we can refer to the class without passing it as an argument)? – Tim Jun 29 '17 at 12:28
  • "self" is an instance of *Const* and "inst" is an instance of class *X*. – Raymond Hettinger Jun 29 '17 at 13:50