getattr() vs __getattr__ vs __getattribute__


There are three methods that are often confusing to the beginners: getattr(), __getattr__, and __getattribute__. This article will try to clear the confusion between these three methods.

getattr()

First of all, getattr() is a built-in function in Python. It can be evoked from anywhere in your code. When called, it returns an attribute of an object. For example:

class User:

    SPECIES = 'human'

    def __init__(self, name):
        self.name = name
    
    def greet(self):
        print(f'Hi, my name is {self.name}')


# Let's first create an instance
john = User('John')

# Now we can use getattr to dynamically find
# class attributes
getattr(john, 'SPECIES')  # -> 'human'

# We can also fetch methods (methods are attributes too)
greet = getattr(john, 'greet')  # -> returns a method
greet()  # now we can call the method

You may wonder why we haven’t used john.SPECIES or john.greet() but sometimes you need a way to dynamically call an attribute of an object, because you don’t know in advance which method will be called.

__getattr__ vs __getattribute__

These two methods are implemented as methods of a class. __getattribute__ is always called. Essentially this method is used to find an attribute of a class. If it fails, it will raise an AttributeError. In case it fails, and class implements __getattr__, then __getattr__ is called right after. Therefore, the biggest difference is that __getattr__ is called for attributes that don’t actually exist on a class.

This is the explanation from the documentation:

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.

If you are looking to implement attribute that is dynamically generated for the class __getattr__ is the method you are looking for. In any case __getattr__ is most probably the thing that you’re looking for, and the reason why you ended up reading this article.

I often find __getattr__ useful when writing wrapper around Python logging:

# logconf.py
import logging
import logging.config
from logging import Logger


class LoggerWrapper:

    def __init__(self):
        # Put your logging config here
        logging.config.dictConfig({
            'version': 1,
            'handlers': {
                'console': {
                    'level': 'DEBUG',
                    'class': 'logging.StreamHandler',
                },
            },
            'loggers': {
                'default': {
                    'handlers': ['console'],
                    'level': 'DEBUG',
                }
            }
        })

        self.logger = logging.getLogger('default')

    def __getattr__(self, name):
        """
        if you call ``debug`` on the instance of this class then
        __getattr__ finds ``debug`` and passes it to self.logger instance
        """
        return getattr(self.logger, name)


logger = LoggerWrapper()

Now, if you import the logger wrapper, you can call all Python logging methods on it, without ever explicitly defined them in your wrapper:

>>> from logconf import logger
>>> logger.info('This is info message')
This is info message
>>> logger.error('This is error message')
This is error message

For example, the info() method is not defined on LoggerWrapper. Therefore, the __getattr__ is called. The logger.info is “transformed” into __getattr__(self, 'info') and it is passed down to getattr(self.logger, 'info'). This returns the corresponding method from the Python logger class, and now this method is called with the original 'This is info message' string.

We're not spammers, and you can opt-out at any moment. We hate spam as much as you do.

powered by TinyLetter

See also