Please consider mentioning property without setter when an attribute can't be set

18 views
Skip to first unread message

Neil Girdhar

unread,
Feb 10, 2022, 5:27:43 PM2/10/22
to python-ideas
Hello,  consider:

class C:
    @property
    def f(self) -> int:
        return 2

class D(C):
    pass

D().f = 2

Gives:

Traceback (most recent call last):
  File "/home/neil/src/cmm/a.py", line 10, in <module>
    D().f = 2
AttributeError: can't set attribute 'f'

This can be a pain to debug when the property is buried in a base class.  Would it make sense to mention the reason why the attribute can't be set, namely that it's on a property without a setter?

Best,

Neil

Steven D'Aprano

unread,
Feb 11, 2022, 4:41:49 AM2/11/22
to python...@python.org
On Thu, Feb 10, 2022 at 02:27:42PM -0800, Neil Girdhar wrote:

> AttributeError: can't set attribute 'f'
>
> This can be a pain to debug when the property is buried in a base class.

> Would it make sense to mention the reason why the attribute can't be set,
> namely that it's on a property without a setter?

I have no objection to changing the error message, I'm sure it's a small
enough change that you should just open a ticket on b.p.o. for it. But I
don't expect that it will be particularly useful either.

If you can't set an attribute on an object, aren't there three obvious
causes to check?

- the object has no __dict__, and so has no attributes at all;
e.g. trying to set an attribute on a float;

- the object has slots, but 'f' is not one of them;

- or 'f' is a property with no setter (or a setter that raises
AttributeError).

Have I missed any common cases?

The error messages are different in each case, but even if they were the
same, there are three obvious causes to check, and property is one of
them.

I suppose that there are exotic failures that could happen in
__getattribute__ or weird descriptors, or metaclass magic, etc, and
*those* might be hard to debug, but it doesn't seem likely to me that a
read-only property will be mysterious.

Especially if you have the object available in the interactive
interpreter, so you can inspect it with the various tools available:

* dir(obj)
* help(obj)
* type(obj).f # Will display <property object at 0x...>

etc. Its hard to keep the existence of a property secret in Python.

So once you know that f is a property, it might be hard to work out
which of the fifty-seven superclasses and mixins it came from *wink* but
that's neither here nor there :-)

Maybe reporting "can't set property 'f'" is good enough.


--
Steve
_______________________________________________
Python-ideas mailing list -- python...@python.org
To unsubscribe send an email to python-id...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at https://mail.python.org/archives/list/python...@python.org/message/Z2AWWETWB72CKARR4DAHB3A2LFRLQR7X/
Code of Conduct: http://python.org/psf/codeofconduct/

Neil Girdhar

unread,
Feb 11, 2022, 5:45:54 AM2/11/22
to python-ideas, python-ideas
I humbly disagree that any of what you wrote is "obvious".

--

---
You received this message because you are subscribed to a topic in the Google Groups "python-ideas" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/python-ideas/IMzPQhK64lw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to python-ideas...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python-ideas/20220211093720.GO16660%40ando.pearwood.info.

Christopher Barker

unread,
Feb 11, 2022, 11:01:23 AM2/11/22
to Neil Girdhar, python-ideas, python-ideas
I have to say I agree with Neil here. I was trying to think about what other reasons an attribute might be unsettable, and did not quickly come up with that list.

And after reading your list, I tried to imagine what I’d tell my beginning students ! 

But if the error message is indeed unique then yes:

 "can't set property 'f'" 

Would be far more clear message. 

-CHB

--
Christopher Barker, PhD (Chris)

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython

Christopher Barker

unread,
Feb 11, 2022, 11:03:24 AM2/11/22
to Neil Girdhar, python-ideas

Eric Fahlgren

unread,
Feb 11, 2022, 1:36:04 PM2/11/22
to Neil Girdhar, python-ideas, python-ideas
Yeah, I have to agree with Neil.  I had exactly this issue a couple years ago, and it took me an hour or two to figure out that it was a property/descriptor-protocol causing the issue, at which point the fix became trivial.  Just knowing to think "it's a property, stupid!" was the hard part and just stating that in the error message would have saved me the frustration.

Paul Moore

unread,
Feb 11, 2022, 2:03:56 PM2/11/22
to Eric Fahlgren, Neil Girdhar, python-ideas, python-ideas
On Fri, 11 Feb 2022 at 18:36, Eric Fahlgren <ericfa...@gmail.com> wrote:
>
> Yeah, I have to agree with Neil. I had exactly this issue a couple years ago, and it took me an hour or two to figure out that it was a property/descriptor-protocol causing the issue, at which point the fix became trivial. Just knowing to think "it's a property, stupid!" was the hard part and just stating that in the error message would have saved me the frustration.

I'm inclined to say just raise an issue on bpo. If it's easy enough,
it'll just get done. If it's hard, having lots of people support the
idea won't make it any easier. I don't think this is something that
particularly needs evidence of community support before asking for it.

Paul
_______________________________________________
Python-ideas mailing list -- python...@python.org
To unsubscribe send an email to python-id...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at https://mail.python.org/archives/list/python...@python.org/message/FSKUTUAMA4A4EK5BN7UPCHZ3D4GF6X74/

Eryk Sun

unread,
Feb 11, 2022, 7:29:52 PM2/11/22
to python-ideas
On 2/11/22, Paul Moore <p.f....@gmail.com> wrote:
>
> I'm inclined to say just raise an issue on bpo. If it's easy enough,
> it'll just get done. If it's hard, having lots of people support the
> idea won't make it any easier. I don't think this is something that
> particularly needs evidence of community support before asking for it.

The error message is in property_descr_set() in Objects/descrobject.c.
I agree that it should state that the attribute is a property. Python
developers know that a property requires a getter, setter, and deleter
method in order to function like a regular, mutable attribute. If not,
help(property) explains it all clearly.
_______________________________________________
Python-ideas mailing list -- python...@python.org
To unsubscribe send an email to python-id...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at https://mail.python.org/archives/list/python...@python.org/message/WBQZMFZT4KCXKEUEND4BNAZFAAUA7HA2/

Steven D'Aprano

unread,
Feb 12, 2022, 8:33:07 PM2/12/22
to python...@python.org
On Fri, Feb 11, 2022 at 08:00:54AM -0800, Christopher Barker wrote:

> I have to say I agree with Neil here. I was trying to think about what
> other reasons an attribute might be unsettable, and did not quickly come up
> with that list.

I'm curious what list you came up with if it excluded the three cases I
suggested (no __dict__, __slots__, property). What other cases are
there?

There's dynamic attributes with __getattr__ and __getattribute__, and
who knows what can be done with metaclass magic, but I'm impressed and
kinda intimidated if they are what came to mind *before* objects without
a dict :-)


> And after reading your list, I tried to imagine what I’d tell my beginning
> students !

Tell them in what context?

Have you already covered properties? If so, then it should be fairly
obvious what to tell them:

"Class, what do you think will happen if you have a property with no
setter and you try to set its value?"

If your class is experienced enough to have learned about classes and
properties, they will surely guess some sort of exception will happen.


> But if the error message is indeed unique then yes:
>
> "can't set property 'f'"
>
> Would be far more clear message.

As I said, I don't object to the change in wording if it is easy
enough to implement.


--
Steve
_______________________________________________
Python-ideas mailing list -- python...@python.org
To unsubscribe send an email to python-id...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at https://mail.python.org/archives/list/python...@python.org/message/47FMU4SUWVULMOBO7HRTXLUJE5LKQAIV/

Christopher Barker

unread,
Feb 13, 2022, 4:01:56 PM2/13/22
to Steven D'Aprano, python-ideas
On Sat, Feb 12, 2022 at 5:32 PM Steven D'Aprano <st...@pearwood.info> wrote:
> I have to say I agree with Neil here. I was trying to think about what
> other reasons an attribute might be unsettable, and did not quickly come up
> with that list.

I'm curious what list you came up with if it excluded the three cases I
suggested (no __dict__, __slots__, property). What other cases are
there?

You're giving me far too much credit -- I hadn't thought about it that much but "no __dict__" was all I cam up with quickly -- and I had no idea what other possibilities there were. (Once I was reminded of__slots__) 
 
> And after reading your list, I tried to imagine what I’d tell my beginning
> students !

Tell them in what context?

Have you already covered properties? If so, then it should be fairly
obvious what to tell them:

"Class, what do you think will happen if you have a property with no
setter and you try to set its value?"

That's the easy part -- we cover that when we cover properties -- this whole thing is not an issue when you are working with your own code that you just added a property to. This issue Neil brought up is that if teh cause is p the chain of superclasses somewhere, you don't get much help from the error message.

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.

> But if the error message is indeed unique then yes:
>
>  "can't set property 'f'"
>
> Would be far more clear message.

As I said, I don't object to the change in wording if it is easy enough to implement.

I think we're all on the same page here.

-CHB

Bruce Leban

unread,
Feb 13, 2022, 4:05:43 PM2/13/22
to Neil Girdhar, Steven D'Aprano, python-ideas
I think the more useful message would be something along the lines of 

        AttributeError: can't set attribute 'f' on object of type 'D'

This will help you track down the error. Steven D'Aprano listed three reasons why it might fail which sounds right but frequently the underlying reason is something else:

You're trying to set the attribute on the wrong object (e.g., element.color vs. element.style.color). I wish more error messages identified the types of the objects involved.

--- Bruce

Eryk Sun

unread,
Feb 13, 2022, 9:07:14 PM2/13/22
to python-ideas
On 2/13/22, Christopher Barker <pyth...@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...@python.org
To unsubscribe send an email to python-id...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at https://mail.python.org/archives/list/python...@python.org/message/3S2KW3O7O7KKBQD2FVW6NG3CISNHF745/

André Roberge

unread,
Feb 15, 2022, 5:12:36 AM2/15/22
to Steven D'Aprano, Python-Ideas
On Fri, Feb 11, 2022 at 5:39 AM Steven D'Aprano <st...@pearwood.info> wrote:
On Thu, Feb 10, 2022 at 02:27:42PM -0800, Neil Girdhar wrote:

> AttributeError: can't set attribute 'f'
>
> This can be a pain to debug when the property is buried in a base class.

> Would it make sense to mention the reason why the attribute can't be set,
> namely that it's on a property without a setter?

I have no objection to changing the error message, I'm sure it's a small
enough change that you should just open a ticket on b.p.o. for it. But I
don't expect that it will be particularly useful either.

If you can't set an attribute on an object, aren't there three obvious
causes to check?

obvious?  See below.

- the object has no __dict__, and so has no attributes at all;
  e.g. trying to set an attribute on a float;

- the object has slots, but 'f' is not one of them;

- or 'f' is a property with no setter (or a setter that raises
  AttributeError).

Have I missed any common cases?

>>> Point = namedtuple('point', ('x', 'y'))
>>> p = Point(2, 3)
>>> p.x = 4

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

Would this qualify as "obvious"?

<snip>

Maybe reporting "can't set property 'f'" is good enough.

+1
André 
Reply all
Reply to author
Forward
0 new messages