# Dive Into Python

Python from novice to pro

Find:

## 4.4. Getting Object References With `getattr`

You already know that Python functions are objects. What you don't know is that you can get a reference to a function without knowing its name until run-time, by using the `getattr` function.

### Example 4.10. Introducing `getattr`

    >>> li = ["Larry", "Curly"]
    >>> li.pop
    <built-in method pop of list object at 010DF884>
    >>> getattr(li, "pop")
    <built-in method pop of list object at 010DF884>
    >>> getattr(li, "append")("Moe")
    >>> li
    ["Larry", "Curly", "Moe"]
    >>> getattr({}, "clear")
    <built-in method clear of dictionary object at 00F113D4>
    >>> getattr((), "pop")
    Traceback (innermost last):
      File "<interactive input>", line 1, in ?
    AttributeError: 'tuple' object has no attribute 'pop'

| This gets a reference to the `pop` method of the list. Note that this is not calling the `pop` method; that would be `li.pop()`. This is the method itself.
| This also returns a reference to the `pop` method, but this time, the method name is specified as a string argument to the `getattr` function. `getattr` is an incredibly useful built-in function that returns any attribute of any object. In this case, the object is a list, and the attribute is the `pop` method.
| In case it hasn't sunk in just how incredibly useful this is, try this: the return value of `getattr` is the method, which you can then call just as if you had said `li.append("Moe")` directly. But you didn't call the function directly; you specified the function name as a string instead.
| `getattr` also works on dictionaries.
| In theory, `getattr` would work on tuples, except that tuples have no methods, so `getattr` will raise an exception no matter what attribute name you give.

### 4.4.1. `getattr` with Modules

`getattr` isn't just for built-in datatypes. It also works on modules.

### Example 4.11. The `getattr` Function in `apihelper.py`

    >>> import odbchelper
    >>> odbchelper.buildConnectionString
    <function buildConnectionString at 00D18DD4>
    >>> getattr(odbchelper, "buildConnectionString")
    <function buildConnectionString at 00D18DD4>
    >>> object = odbchelper
    >>> method = "buildConnectionString"
    >>> getattr(object, method)
    <function buildConnectionString at 00D18DD4>
    >>> type(getattr(object, method))
    <type 'function'>
    >>> import types
    >>> type(getattr(object, method)) == types.FunctionType
    True
    >>> callable(getattr(object, method))
    True

| This returns a reference to the `buildConnectionString` function in the `odbchelper` module, which you studied in Chapter 2, Your First Python Program. (The hex address you see is specific to my machine; your output will be different.)
| Using `getattr`, you can get the same reference to the same function. In general, ``getattr`(object, "attribute")` is equivalent to `object.attribute`. If `object` is a module, then `attribute` can be anything defined in the module: a function, class, or global variable.
| And this is what you actually use in the `info` function. `object` is passed into the function as an argument; `method` is a string which is the name of a method or function.
| In this case, `method` is the name of a function, which you can prove by getting its `type`.
| Since `method` is a function, it is callable.

### 4.4.2. `getattr` As a Dispatcher

A common usage pattern of `getattr` is as a dispatcher. For example, if you had a program that could output data in a variety of different formats, you could define separate functions for each output format and use a single dispatch function to call the right one.

For example, let's imagine a program that prints site statistics in HTML, XML, and plain text formats. The choice of output format could be specified on the command line, or stored in a configuration file. A `statsout` module defines three functions, `output_html`, `output_xml`, and `output_text`. Then the main program defines a single output function, like this:

### Example 4.12. Creating a Dispatcher with `getattr`

    import statsout

    def output(data, format="text"):
        output_function = getattr(statsout, "output_%s" % format)
        return output_function(data)

| The `output` function takes one required argument, `data`, and one optional argument, `format`. If `format` is not specified, it defaults to `text`, and you will end up calling the plain text output function.
| You concatenate the `format` argument with "output_" to produce a function name, and then go get that function from the `statsout` module. This allows you to easily extend the program later to support other output formats, without changing this dispatch function. Just add another function to `statsout` named, for instance, `output_pdf`, and pass "pdf" as the `format` into the `output` function.
| Now you can simply call the output function in the same way as any other function. The `output_function` variable is a reference to the appropriate function from the `statsout` module.

Did you see the bug in the previous example? This is a very loose coupling of strings and functions, and there is no error checking. What happens if the user passes in a format that doesn't have a corresponding function defined in `statsout`? Well, `getattr` will return `None`, which will be assigned to `output_function` instead of a valid function, and the next line that attempts to call that function will crash and raise an exception. That's bad.

Luckily, `getattr` takes an optional third argument, a default value.

### Example 4.13. `getattr` Default Values

    import statsout

    def output(data, format="text"):
        output_function = getattr(statsout, "output_%s" % format, statsout.output_text)
        return output_function(data)

| This function call is guaranteed to work, because you added a third argument to the call to `getattr`. The third argument is a default value that is returned if the attribute or method specified by the second argument wasn't found.

As you can see, `getattr` is quite powerful. It is the heart of introspection, and you'll see even more powerful examples of it in later chapters.