Tim
Tim

Reputation: 99526

Problems creating a "constant" descriptor class for 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

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.

Upvotes: -2

Views: 307

Answers (1)

Raymond Hettinger
Raymond Hettinger

Reputation: 226624

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):
        object.__setattr__(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

Upvotes: 3

Related Questions