classification
Title: Possible wrong method name in attribute references doc
Type: behavior Stage: resolved
Components: Documentation Versions: Python 3.8, Python 3.7, Python 3.6, Python 3.4, Python 3.5
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: docs@python Nosy List: cheryl.sabella, denis-osipov, docs@python, steven.daprano
Priority: normal Keywords:

Created on 2018-11-04 17:43 by denis-osipov, last changed 2019-03-26 23:00 by cheryl.sabella. This issue is now closed.

Messages (4)
msg329245 - (view) Author: Denis Osipov (denis-osipov) * Date: 2018-11-04 17:43
6.3.1. Attribute references says:

"The primary must evaluate to an object of a type that supports attribute references, which most objects do. This object is then asked to produce the attribute whose name is the identifier. This production can be customized by overriding the __getattr__() method. If this attribute is not available, the exception AttributeError is raised."

It seems that __getattribute__ method is meaning.
msg329274 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2018-11-04 23:12
https://docs.python.org/3/reference/expressions.html#attribute-references

__getattr__ is the correct method to override in most (but not all) cases. I don't think we should encourage people to override __getattribute__ as the first resort.

__getattribute__ is a more specialised method that is used by the interpreter at a deeper level. It is called on every attribute access, so it ought to be as fast as possible, while __getattr__ is only called if the named attribute doesn't exist.

I don't think anything needs to change here.
msg329288 - (view) Author: Denis Osipov (denis-osipov) * Date: 2018-11-05 09:45
Got it.

But now docs says that overriding the __getattr__() method is enough to customize attribute access. It's not completely true.

If I understand it correct, to make __getattr__() work every time you need to call it by __getattribute__ or raise AttributeError, e.g. store attributes somewhere not in instance __dict__. In this case you need to override __setattr__ too.

class MyGetattrClass:
    def __init__(self):
        super().__setattr__("attrs", {})

    def __setattr__(self, name, value):
        self.attrs[name] = value

    def __getattr__(self, name):
        try:
            print(f"{name} equals {self.attrs[name]}")
        except KeyError:
            raise AttributeError(
                f"{type(self).__name__!r} object has no attribute {name!r}"
            ) from None

If it's correct, we probably should add some clarification in expressions doc. Or maybe just link to https://docs.python.org/3/reference/datamodel.html#object.__getattr__ (which mention about it) will be enough.
msg338921 - (view) Author: Cheryl Sabella (cheryl.sabella) * (Python committer) Date: 2019-03-26 23:00
> Or maybe just link to https://docs.python.org/3/reference/datamodel.html#object.__getattr__ (which mention about it) will be enough.

In section 6.3.1, __getattr__() is already linked to the datamodel page referenced.  

As your suggested change is already in the docs, I'm going to close this.
History
Date User Action Args
2019-03-26 23:00:32cheryl.sabellasetstatus: open -> closed

nosy: + cheryl.sabella
messages: + msg338921

resolution: not a bug
stage: resolved
2018-11-05 09:45:47denis-osipovsetmessages: + msg329288
2018-11-04 23:12:15steven.dapranosetnosy: + steven.daprano
messages: + msg329274
2018-11-04 17:43:20denis-osipovcreate