Difference Between _Getattr_ and _Getattribute_

Difference between __getattr__ and __getattribute__

A key difference between __getattr__ and __getattribute__ is that __getattr__ is only invoked if the attribute wasn't found the usual ways. It's good for implementing a fallback for missing attributes, and is probably the one of two you want.

__getattribute__ is invoked before looking at the actual attributes on the object, and so can be tricky to implement correctly. You can end up in infinite recursions very easily.

New-style classes derive from object, old-style classes are those in Python 2.x with no explicit base class. But the distinction between old-style and new-style classes is not the important one when choosing between __getattr__ and __getattribute__.

You almost certainly want __getattr__.

Understanding the difference between __getattr__ and __getattribute__

Some basics first.

With objects, you need to deal with their attributes. Ordinarily, we do instance.attribute. Sometimes we need more control (when we do not know the name of the attribute in advance).

For example, instance.attribute would become getattr(instance, attribute_name). Using this model, we can get the attribute by supplying the attribute_name as a string.

Use of __getattr__

You can also tell a class how to deal with attributes which it doesn't explicitly manage and do that via __getattr__ method.

Python will call this method whenever you request an attribute that hasn't already been defined, so you can define what to do with it.

A classic use case:

class A(dict):
def __getattr__(self, name):
return self[name]
a = A()
# Now a.somekey will give a['somekey']

Caveats and use of __getattribute__

If you need to catch every attribute regardless whether it exists or not, use __getattribute__ instead. The difference is that __getattr__ only gets called for attributes that don't actually exist. If you set an attribute directly, referencing that attribute will retrieve it without calling __getattr__.

__getattribute__ is called all the times.

Some questions about __getattr__ and __getattribute__?

The __getattribute__, __setattr__ and __delattr__ methods are called for all attribute access (getting, setting and deleting). __getattr__ on the other hand is only called for missing attributes; it is not normally already implemented, but if it is then __getattribute__ calls it if it could not otherwise locate the attribute, or if an AttributeError was raised by __getattribute__.

You replaced the standard implementations of the 3 main methods with methods that do nothing but print and return None (the default in the absence of an explicit return statement). __dict__ is just another attribute access, and your __getattribute__ method returns None, and never itself calls __getattr__ or raises an AttributeError.

From the Customizing attribute access documentation:

object.__getattr__(self, name)
Called when an attribute lookup has not found the attribute in the usual places (i.e. it is not an instance attribute nor is it found in the class tree for self).

and

object.__getattribute__(self, name)
Called unconditionally to implement attribute accesses for instances of the class. If the class also defines __getattr__(), the latter will not be called unless __getattribute__() either calls it explicitly or raises an AttributeError.

(Bold emphasis mine).

Either call the base implementation (via super().__getattribute__) or raise an AttributeError:

>>> class B:
... def __init__(self):
... self.name = '234'
... def __getattribute__(self, name):
... print('getattr')
... return super().__getattribute__(name)
... def __getattr__(self, name):
... print('get')
... def __setattr__(self, name, value):
... print('set')
... def __delattr__(self, name):
... print('del')
...
>>> b = B()
set
>>> b.__dict__
getattr
{}
>>> b.name
getattr
get
>>> class B:
... def __init__(self):
... self.name = '234'
... def __getattribute__(self, name):
... print('getattr')
... raise AttributeError(name)
... def __getattr__(self, name):
... print('get')
... def __setattr__(self, name, value):
... print('set')
... def __delattr__(self, name):
... print('del')
...
>>> b = B()
set
>>> b.__dict__
getattr
get
>>> b.name
getattr
get

Note that by calling super().__getattribute__ the actual __dict__ attribute is found. By raising an AttributeError instead, __getattr__ was called, which also returned None.

What is the difference between type.__getattribute__ and object.__getattribute__?

You are operating directly on classes. object.__getattribute__ is only used on instances of A and B instead. That's because special methods are looked up on the type; for instances the type is the class.

For classes then, the type is.. type:

>>> class A:
... f = 1
...
>>> class B(A):
... pass
...
>>> type(B)
<class 'type'>

so type.__getattribute__ is used:

>>> type.__getattribute__(B, 'f')
1

and object.__getattribute__ works fine on instances:

>>> object.__getattribute__(B(), 'f')
1

For instances attributes are looked up first on the class (in the case of data descriptors), then on the instance, then if the instance doesn't have the attribute, the class hierarchy is searched in MRO order. This is the job of object.__getattribute__. So object.__getattribute__ looks at the first argument (e.g. self, the instance object) for the attribute, and at objects in type(self).__mro__.

For classes, attributes are looked up on the class itself and all its bases; type.__getattribute__ looks directly at self.__mro__ for these; self being a class object here.

If you use object.__getattribute__ for classes then, there is no f attribute on B directly, and no f anywhere in type(B).__mro__. If you use type.__getattribute__, A is a member of B.__mro__ so f is found there:

>>> type(B).__mro__
(<class 'type'>, <class 'object'>)
>>> B.__mro__
(<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

Difference between __getattribute__ and obj.__dict__['x'] in python?

__getattribute__() method is for lower level attribute processing.

Default implementation tries to find the name
in the internal __dict__ (or __slots__). If the attribute is not found, it calls __getattr__().

UPDATE (as in the comment):

They are different ways for finding attributes in the Python data model. They are internal methods designed to fallback properly in any possible situation. A clue: "The machinery is in object.__getattribute__() which transforms b.x into type(b).__dict__['x'].__get__(b, type(b))." from docs.python.org/3/howto/descriptor.html

What is the relationship between __getattr__ and getattr?

Alex's answer was good, but providing you with a sample code since you asked for it :)

class foo:
def __init__(self):
self.a = "a"
def __getattr__(self, attribute):
return "You asked for %s, but I'm giving you default" % attribute

>>> bar = foo()
>>> bar.a
'a'
>>> bar.b
"You asked for b, but I'm giving you default"
>>> getattr(bar, "a")
'a'
>>> getattr(bar, "b")
"You asked for b, but I'm giving you default"

So in short answer is

You use

__getattr__ to define how to handle attributes that are not found

and

getattr to get the attributes

What are some rules of thumb for deciding between __get__, __getattr__, and __getattribute__?

__setattribute__ does not exist because __setattr__ is always called. __getattr__ is only called for f.x if the attribute lookup fails via the normal channel (which is provided by __getattribute__, so that function is similarly always called).

The descriptor protocol is slightly orthogonal to the others. Given

class Foo(object):
def __init__(self):
self.x = 5

f = Foo()

The following are true:

  • f.x would invoke f.__getattribute__('x') if it were defined.
  • f.x would not invoke f.__getattr__('x') if it were defined.
  • f.y would invoke f.__getattr__('y') if it were defined, or else
    f.__getattribute__('y') if it were defined.

The descriptor is invoked by an attribute, rather than for an attribute. That is:

class MyDescriptor(object):
def __get__(...):
pass
def __set__(...):
pass

class Foo(object):
x = MyDescriptor()

f = Foo()

Now, f.x would cause type(f).__dict__['x'].__get__ to be called, and f.x = 3 would call type(f).__dict__['x'].__set__(3).

That is, Foo.__getattr__ and Foo.__getattribute__ would be used to find what f.x references; once you have that, f.x produces the result of type(f.x).__get__() if defined, and f.x = y invokes f.x.__set__(y) if defined.

(The above calls to __get__ and __set__ are only approximately correct, since I've left out the details of what arguments __get__ and __set__ actually receive, but this should be enough to explain the difference between __get__ and __getattr[ibute]__.)

Put yet another way, if MyDescriptor did not define __get__, then f.x would simply return the instance of MyDescriptor.



Related Topics



Leave a reply



Submit