pythondescriptorslots

Object has no attribute when setting an attribute declared in__slots__ with desciptors


I have this class which uses slots and descriptors. I put the name of the variables in __slots__ and use descriptors to set their values.

class Example:
    __slots__ =  ('__x', '__y') #see the double undescores
    _x = descriptor_of_x()
    _y = descriptor_of_y()

    def __init__(self, x, y):
        self._x = x
        self._y = y

The descriptors look like this.

class descriptor_of_x:
    __slots__ = ('name')
    def __set_name__(self, owner, name):
        # the name of the variable that will be set is 
        # the name of the variable that called it prepended with a underscore.
        self.name = f"_{name}" 

    def __set__(self, obj, value):
        setattr(obj, self.name, value)

    def __get__(self, obj, objtype=None):
        return getattr(obj, self.name)

When I run this I get:

'Example' object has no attribute '__x'

when I remove the __slots__ and then use vars() on the instance for Example, I can clearly see __x and __y in the resulting dict.

So, the names are correct, I definitely put them in the slots but it can't find them.

What am I missing here? Are the variables being declared before __slots__ is?


Solution

  • from te docs:

    the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam

    When the slots is created, the items with the double underscores get renamed, that is why they can't be found.

    changed the desciptors to append an underscore instead of prepend and now the variables in slots should be _x_ and _y_, this now works.