Using Functions as Objects
00:00 In the previous lesson, I explained the three high-level programming approaches. In this lesson, I’ll show you how functions are objects in Python. Let’s dive right into the REPL and play around.
00:12 Let’s start out by creating a simple function
00:20
and now let me call it, well, hello there to you too. Hopefully this wasn’t a surprise. Stop and consider for a moment just what those parentheses on the end of say_hello are for.
00:33 That’s what tells Python to invoke the function of that name. But what happens if you leave them off?
00:41
Functions in Python are objects. Without the parentheses, the REPL evaluates it telling you what it is. In this case, it tells you that it’s a function that has the name say_hello, and then there’s an object address reference.
00:54
That number is a unique value within the interpreter having to do with where it’s stored. You can more or less ignore it, although sometimes when you’re using the interpreter it can be handy to see if two things that have the same content are actually a reference to the same thing in memory. Since say_hello is an object, I can create a new reference to it.
01:16
This is no different than something like x = 1 then y = x. I’ve created a new reference pointing to the same object, and since it points to the same thing, I can use parentheses on it to invoke the corresponding code.
01:31
This goes for more than just the functions you define. print is a built-in function. When you examine a reference to it, you get similar output to above. Because it ships with Python, the information’s a little different, but it is the same idea.
01:47
Back in the intro, I said you could write most of the code I’m showing you even in very old versions of Python. This would be the exception, as print used to be a statement, but became a built-in function in Python 3. The print function takes arguments.
02:07
Here I’ve passed it a single argument, which is a string, which print then outputs to the screen. It’s kind of print’s purpose.
02:23
print can also take multiple arguments and they don’t have to be strings. If they’re not, it converts them to text for printing. If you give it multiple arguments, it outputs each of them separated by a space.
02:35 There are ways of changing that, but that’s not important here. Since functions are objects,
02:47
I can pass a reference to the say_hello function into print as an argument. Remember, I’m not invoking it here. I’m treating it like data. The result is print outputs the same thing that the REPL evaluation showed just a few lines ago, which of course means, yep, you can print() a reference to print. Python’s dir() function returns a list of all the properties of an object.
03:17 There’s a lot of stuff in here, and that’s because every object in Python inherits from a default object that includes a bunch of special methods and properties.
03:25 Python notes that they’re special by using leading and trailing double underscores. These are known as dunder methods. This might feel like a bit of a tangent, but give me a second.
03:39
Since a function is an object, like with any other object, I can dynamically add a new property to it. Here I’ve created a property called language and inside of it, I’m storing the string 'en'. Like with any other property, I can evaluate it in the REPL.
03:57
If I call dir() on this again,
04:02
you can see that 'language' has been added to the list of things associated with the function object. Okay, it’s time to define a couple more functions.
04:10
First, something similar to say_hello.
04:19 Now, something a little different. Not that it’s completely different, just a little different. Obscure Monty Python reference for the win.
04:35
The outside function takes an argument. That’s something I hope you’ve seen before. The little difference part is that on the second line of outside, the argument gets invoked with parentheses.
04:45
The expectation here is that the argument passed into outside is a function reference. If it isn’t, invoking it will cause an exception. Clicks call outside(), passing it inside.
04:58
Remember, the argument to outside is a reference to the inside function. The second line of outside invokes inside, resulting in the second line of output.
05:08
I know I’m being repetitive and bashing this kind of hard, but to show the difference, let’s try using parentheses on inside. Before I do it, let me pause here for a second.
05:17 Take a moment to predict what will happen. Will you see output? If so, what will it be? Will there be an error? What kind? Okay, time’s up. Let’s try this out. Some printing happened and an exception got raised.
05:34
The error object is not callable due to the attempt to use the parentheses to invoke an object that can’t be invoked, but why NoneType? Well, let’s examine this from the inside out.
05:47
Because the parentheses are here, it means inside is getting invoked right there. This is before it’s passed as an argument. That’s why this print happens first. inside got called.
06:01
What gets passed as the argument to outside is the return value from inside. In Python, all functions return something even if you don’t explicitly ask them to.
06:13
In fact, if you don’t use the return statement, what comes back is None. So here None is what’s being passed as the argument to outside.
06:22
The first thing outside does is print this output and then it tries to invoke this argument, but since the argument this time was actually the return value of inside instead of a reference to a function, and that return value was None, this line is attempting to call None, which isn’t allowed.
06:41 The result being the exception on the screen. All this has been a little abstract. Let’s look at an example where this actually gets used. First, I need a list.
07:00
The built-in sorted() function returns a sorted copy of the original animal’s list. Consider the length of strings in the original list.
07:17
This quick for loop shows the value and the length of each value in the animal’s list. You get the length of an animal’s string by calling the built-in len() function.
07:26
The important part of that sentence was “function”. Say you wanted to sort by the length of the string rather than alphabetically. The sorted() function lets you do this.
07:34 In fact, it supports the use of an arbitrary comparison mechanism by passing in a reference to a function that it then invokes and uses the result to compare as the basis for the order.
07:50
sorts by the string length. This is kind of like the outside function above. You pass in len and sorted() invokes it for each item in the iterable being sorted.
08:00
It then uses the return value to determine the sort order. In this case, since len returns the length, the sort is based on the length, smallest value first.
08:11 Sometimes, you want a quick inline function-like thing for one-off usage. Python’s version of these are called lambdas. I’ll show you those next.
Become a Member to join the conversation.
