You are here: Home > Dive Into Python > The Power Of Introspection > Getting Object References With getattr | << >> | ||||
Dive Into PythonPython from novice to pro |
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.
>>> 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. |
getattr isn't just for built-in datatypes. It also works on modules.
>>> 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. |
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:
import statsout def output(data, format="text"): output_function = getattr(statsout, "output_%s" % format) return output_function(data)
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.
import statsout def output(data, format="text"): output_function = getattr(statsout, "output_%s" % format, statsout.output_text) return output_function(data)
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.
<< Using type, str, dir, and Other Built-In Functions |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
Filtering Lists >> |