Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I implement __getattribute__ without an infinite recursion error?

I want to override access to one variable in a class, but return all others normally. How do I accomplish this with __getattribute__?

I tried the following (which should also illustrate what I'm trying to do) but I get a recursion error:

class D(object):     def __init__(self):         self.test=20         self.test2=21     def __getattribute__(self,name):         if name=='test':             return 0.         else:             return self.__dict__[name]  >>> print D().test 0.0 >>> print D().test2 ... RuntimeError: maximum recursion depth exceeded in cmp 
like image 870
Greg Avatar asked Dec 16 '08 16:12

Greg


People also ask

What is __ Getattribute __ in Python?

__getattribute__This method should return the (computed) attribute value or raise an AttributeError exception. In order to avoid infinite recursion in this method, its implementation should always call the base class method with the same name to access any attributes it needs, for example, object.

What is __ Getattribute__ used for?

The object's method __getattribute__() is used to retrieve an attribute from an instance. It captures every attempt to access an instance attribute by using dot notation or getattr() built-in function. Unless it was overridden, the former expression is translated into object.

How do you find the attributes of an object in Python?

Attributes of a class can also be accessed using the following built-in methods and functions : getattr() – This function is used to access the attribute of object. hasattr() – This function is used to check if an attribute exist or not. setattr() – This function is used to set an attribute.


2 Answers

You get a recursion error because your attempt to access the self.__dict__ attribute inside __getattribute__ invokes your __getattribute__ again. If you use object's __getattribute__ instead, it works:

class D(object):     def __init__(self):         self.test=20         self.test2=21     def __getattribute__(self,name):         if name=='test':             return 0.         else:             return object.__getattribute__(self, name) 

This works because object (in this example) is the base class. By calling the base version of __getattribute__ you avoid the recursive hell you were in before.

Ipython output with code in foo.py:

In [1]: from foo import *  In [2]: d = D()  In [3]: d.test Out[3]: 0.0  In [4]: d.test2 Out[4]: 21 

Update:

There's something in the section titled More attribute access for new-style classes in the current documentation, where they recommend doing exactly this to avoid the infinite recursion.

like image 85
Egil Avatar answered Sep 29 '22 08:09

Egil


Actually, I believe you want to use the __getattr__ special method instead.

Quote from the Python docs:

__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). name is the attribute name. This method should return the (computed) attribute value or raise an AttributeError exception.
Note that if the attribute is found through the normal mechanism, __getattr__() is not called. (This is an intentional asymmetry between __getattr__() and __setattr__().) This is done both for efficiency reasons and because otherwise __setattr__() would have no way to access other attributes of the instance. Note that at least for instance variables, you can fake total control by not inserting any values in the instance attribute dictionary (but instead inserting them in another object). See the __getattribute__() method below for a way to actually get total control in new-style classes.

Note: for this to work, the instance should not have a test attribute, so the line self.test=20 should be removed.

like image 43
tzot Avatar answered Sep 29 '22 07:09

tzot