On 2/13/22, Christopher Barker <python...@gmail.com> wrote:
>
> Telling newbies that that means that it's either a property with no setter,
> or am object without a __dict__, or one with  __slots__ defined is not
> really very helpful.

The __slots__ case is due to the lack of a __dict__ slot.  It can be
manually added in __slots__ (though adding __dict__ back is uncommon),
along with the __weakref__ slot.

The exception message when there's no __dict__ is generally good
enough. For example:

    >>> (1).x = None
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'int' object has no attribute 'x'

It's clear that the object has no __dict__ and no descriptor named
"x". However, the message gets confusing with partially implemented
magic attributes.

For example, implement __getattr__(), but not __setattr__() or __delattr__():

    class C:
        __slots__ = ()
        def __getattr__(self, name):
            class_name = self.__class__.__name__
            if name == 'x':
                return 42
            raise AttributeError(f'{class_name!r} object has no '
                                 f'attribute {name!r}')

    >>> c = C()
    >>> c.x
    42
    >>> c.x = None
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'C' object has no attribute 'x'

Add __setattr__():

        def __setattr__(self, name, value):
            class_name = self.__class__.__name__
            if name == 'x':
                raise AttributeError(f'attribute {name!r} of {class_name!r} '
                                      'objects is not writable')
            raise AttributeError(f'{class_name!r} object has no '
                                 f'attribute {name!r}')

    >>> c = C()
    >>> c.x = None
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 12, in __setattr__
    AttributeError: attribute 'x' of 'C' objects is not writable
    >>> del c.x
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'C' object has no attribute 'x'

Add __delattr__():

        def __delattr__(self, name):
            class_name = self.__class__.__name__
            if name == 'x':
                raise AttributeError(f'attribute {name!r} of {class_name!r} '
                                      'objects is not writable')
            raise AttributeError(f'{class_name!r} object has no '
                                 f'attribute {name!r}')

    >>> c = C()
    >>> c.x
    42
    >>> c.x = None
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 12, in __setattr__
    AttributeError: attribute 'x' of 'C' objects is not writable
    >>> del c.x
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 19, in __delattr__
    AttributeError: attribute 'x' of 'C' objects is not writable
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/3S2KW3O7O7KKBQD2FVW6NG3CISNHF745/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to