David542
David542

Reputation: 110163

When to use __getattr__

I came across the __getattr__ built-in and was wondering when it would be used. I had a hard time thinking of a practical use from the documentation
http://docs.python.org/reference/datamodel.html#. What would be an actual example of how it could be used and useful in code?

Upvotes: 4

Views: 2779

Answers (4)

Colin Dunklau
Colin Dunklau

Reputation: 3111

Edit: This is about the built-in function getattr, not the __getattr__ method.

I needed to do this for a REST client using bearer tokens. I wrapped Requests's Session object into my own interface so I could always send the auth header, and (more relevantly) make HTTP requests to the same site, just using the URL's path.

class RequestsWrapper():
    def __init__(self, base_url):
        self.client = requests.Session(
            headers={'Authorization':'myauthtoken'}
        )
        self.base_url = base_url

    def _make_path_request(self, http_method, path, **kwargs):
        """
        Use the http_method string to find the requests.Session instance's
        method.
        """
        method_to_call = getattr(self.client, http_method.lower())
        return method_to_call(self.base_url + path, **kwargs)

    def path_get(self, path, **kwargs):
        """ 
        Sends a GET request to base_url + path.
        """
        return self._make_path_request('get', path, **kwargs)

    def path_post(self, path, **kwargs):
        """ 
        Sends a POST request to base_url + path.
        """
        return self._make_path_request('post', path, **kwargs)

    def path_put(self, path, **kwargs):
        """ 
        Sends a PUT request to base_url + path.
        """
        return self._make_path_request('put', path, **kwargs)

    def path_delete(self, path, **kwargs):
        """ 
        Sends a DELETE request to base_url + path.
        """
        return self._make_path_request('delete', path, **kwargs)

Then, I could just make a request based on the path:

# Initialize
myclient = RequestsWrapper("http://www.example.com")
# Make a get request to http://www.example.com/api/spam/eggs
response = myclient.path_get("/api/spam/eggs")
# Print the response JSON data
if response.ok:
    print response.json

Upvotes: 2

Chris
Chris

Reputation: 46316

One example is to use object notation with dictionaries. For example, consider a dictionary

myDict = {'value': 1}

Typically in Python one accesses the 'value' variable as

myDict['value']

which will print 1 at the Python interpreter. However, one may wish to use the myDict.value notation. This may be achieved by using the following class:

class DictAsMember(dict):
    def __getattr__(self, name):
        value = self[name]
        if isinstance(value, dict):
            value = DictAsMember(value)
        return value

my_dict = DictAsMember()
my_dict['property'] = {'sub_property': 1}

print(my_dict.property.sub_property) # 1 will be printed

Upvotes: 10

Casey Kuball
Casey Kuball

Reputation: 7955

Since __getattr__ is only called when an attribute is not found, it can be a useful way to define an alternate place to look up an attribute, or to give default values, similar to a defaultdict.

You could also emulate a base class higher than all the others in an object's MRO, by delegating all the lookups here to another object (though doing this you could potentially have an infinite loop if the other object is delegating the attribute back).

There is also __getattribute__, which is related in that it is called anytime any attribute is looked up on the object.

Upvotes: 3

Pierre
Pierre

Reputation: 6172

An example usage would be to create a simple wrapper around some object. In order, for example, to log the calls, or modify its behavior without inheriting from it, and without having to implement the whole interface of the object.

There is several good documented examples out there, like, for example, http://western-skies.blogspot.fr/2008/02/complete-example-of-getattr-in-python.html.

Upvotes: 3

Related Questions