classification
Title: __dict__ attribute is incorrectly stated to be read-only
Type: enhancement Stage:
Components: Documentation Versions: Python 3.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: docs@python Nosy List: docs@python, reed, steven.daprano
Priority: normal Keywords:

Created on 2019-09-11 06:21 by reed, last changed 2019-09-11 18:04 by reed.

Messages (4)
msg351765 - (view) Author: Reed (reed) Date: 2019-09-11 06:21
The documentation in this section (https://docs.python.org/3/library/stdtypes.html#special-attributes) states that the __dict__ attribute, and several others, are read-only. In particular, it states:

"The implementation adds a few special read-only attributes to several object types, where they are relevant."

Then it lists several attributes, including __dict__. However, __dict__ is writable. For example:

    class A: pass 
    A().__dict__ = {'x': 1}

Most other listed attributes, such as __class__ and __name__, are writable as well. They should not be documented as read-only.

(Also, I'm not sure why the documentation lists object.__dict__ and instance.__class__. What is the difference between an object and an instance?)
msg351771 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2019-09-11 08:57
"The implementation adds a few special read-only attributes to several object TYPES" [emphasis added]

py> class MyType:
...     pass
...
py> MyType.__dict__ = {}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: attribute '__dict__' of 'type' objects is not writable



> What is the difference between an object and an instance?

In general, nothing. But ``object.__dict__`` refers to the special builtin *class* called "object". In hindsight, we should have called it Object, so we could more easily distinguish between the *class* called "object" and *instances* of that class.


py> print(object)  # the class/type itself
<class 'object'>

py> print(object())  # an instance of object
<object object at 0xb7ce1cd0>

The docs are correct here, but if you care to suggest some improvements, we will consider them.
msg351772 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2019-09-11 09:02
Oh, another point... 

Python is a little more complicated than some other languages, like Java, because Python classes (types) are themselves instances (objects) of yet another class (the so called "metaclass"). Ultimately, all classes are instances of the special metaclass called "type".

So all instances are objects, and all classes are also objects.

This is really powerful and useful, but it does sometimes make it hard to talk about things :-)
msg352007 - (view) Author: Reed (reed) Date: 2019-09-11 18:04
Thank you for the clarification. I didn't realize the section only referred to types, but it makes sense now that I read the documentation more carefully.

The documentation is still incorrect for certain attributes (e.g. __bases__ and __name__) as they can be mutated. For example:

    class A: pass
    A.__name__ = 'AA'

    class B(A): pass
    class C(B): pass
    C.__bases__ = (A,)

Also, this documentation is incorrectly linked to by other parts of the documentation. For example, in https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy, there is the sentence:

"Special attributes: __dict__ is the attribute dictionary; __class__ is the instance’s class."

__dict__ and __class__ link to the documentation about types, and yet that sentence is referring to all instances of any class (such as `A()`), not just type objects (such as `A`).

In terms of concrete improves, I would suggest:
    * Adding a section somewhere describing __dict__ and __class__ for all instances, not just types. Or change the original section to refer to all instances.

Assuming the original section is not changed to refer to all instances:
    * In the sentence "The implementation adds a few special read-only attributes to several object types", replace "object types" with "types" or "instances whose class subclasses from `type`" 
    * Replace `instance.class` with `class.class`. The phrase `instance` is confusing, as it then describes `class.__bases__`, which does explicitly use the word "class" to indicate it only applies to classes.
History
Date User Action Args
2019-09-11 18:04:04reedsetmessages: + msg352007
2019-09-11 09:02:34steven.dapranosetmessages: + msg351772
2019-09-11 08:57:58steven.dapranosetnosy: + steven.daprano
messages: + msg351771
2019-09-11 06:21:11reedcreate