You probably know that in Python, everything is an object. Objects have attributes that can represent data (e.g., numbers or strings), but they can also contain executable codes. These are known as callable objects.
Functions are also objects, and as such, they have certain built-in attributes by default. These include __name__, which holds the name given in the function definition, and __doc__, which stores the function’s documentation string describing its purpose and parameters.
When you define your own function, you can also assign custom attributes to it.
This sounds interesting, but you might wonder what the point is of giving a function attributes. It’s a valid question, since the essence of a function is usually defined by its parameters, the sequence of statements it executes, and the return value. So is there really anything else that needs to be added?
The answer is no — adding extra attributes is not necessary. However, it is possible, and in some cases, doing so can be quite useful. In the e-book Python Knowledge Building Step by Step, you’ll find several examples of how to use this technique, ranging from adding metadata to retrieving internal values calculated within the function.
Now, for illustrative purposes, we define a simple function that calculates the hypotenuse of a right-angled triangle using its two legs. However, for some reason, we also need the squares of the legs and the hypotenuse every time this function is called. Since the function is only allowed to return the hypotenuse, we store the squared values in separate attributes, which can be accessed after the function call. This is demonstrated in the code below:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
def hypotenuse(a, b): hypotenuse.a2 = a**2 hypotenuse.b2 = b**2 hypotenuse.c2 = hypotenuse.a2 + hypotenuse.b2 return pow(hypotenuse.c2, 0.5) # TEST print(hypotenuse(3, 4)) # Output: 5.0 print(hypotenuse.a2) # Output: 9 print(hypotenuse.b2) # Output: 16 print(hypotenuse.c2) # Output: 25 |
It should be noted that assigning attributes to function objects is not a common programming practice. This is partly because a function’s metadata can usually be accessed in other ways, and partly because defining attributes within the function can obscure the logic of its implementation. Nevertheless, it is a useful technique to be aware of and to apply when appropriate.