Writing Cleaner Code
00:00 In the previous lesson, I showed you the class methods and attributes on named tuples. In this lesson, I’ll be talking about how to use named tuples to write more readable Python.
00:11 There are several situations where you might choose to use a named tuple to make your code more readable. You’ve already seen how using a dot notation name can be better than a tuple index. If your function returns multiple values, returning a named tuple may make the result easier to understand.
00:27 For functions with long signatures, you can replace some of the arguments with a named tuple. And finally, I’ll show you how named tuples can make your data code easier to read.
00:39 I’ve mentioned how naming the parts of a tuple can be useful, but let me show you an example.
00:51
Consider a variable that contains information about a line being drawn to your screen. This is sometimes called a pen. My vanilla tuple here contains a width, a style description, and a Boolean to indicate whether or not the bevel behavior is on. Now, pretend you’re further down in your source code, far away from the definition of pen
and the associated comment. You see the following.
01:24
Just what is the first spot in the pen
tuple? Well, you have to remember or go looking earlier in the file for your declaration. Let’s see the alternative.
02:00
It doesn’t matter now how far apart the declaration and the use are. pen.width
is far more understandable than pen[0]
. Readability for the win.
02:13
One of Python’s built-in functions is divmod()
. My example here divides 9
by 4
and returns a tuple containing the quotient and the remainder. Any time you use divmod()
, you have to remember what is meant by each part of the tuple.
02:29 Let’s see if I can make this clearer by using a named tuple.
02:57
By returning a named tuple, my custom version of divmod()
is much clearer. The parts of the tuple are named, and so you only have to remember what a quotient is rather than guess at its purpose. This example is a bit contrived in order to keep the function short, but hopefully you get the idea.
03:13 Returning a named tuple gives a nice encapsulation of your result and makes it clear to the next programmer—which could always be you—what each part of the return value is for.
03:27 Consider the following function signature for creating a user. As an alternative, you can use a named tuple as an argument to the function. This encapsulates all the parts of the user together.
03:39
Not only does it shorten the function signature, but within the function, it keeps the related pieces of data within the same object. The code here is a little unrealistic, as it’s all in one place so I could show you the idea. If you were actually using this, the capital-U User
class and the function would be in the same module, whereas the programmer calling the create_user()
function would likely be importing the User
class and the function into another file.
04:06
The User
class would get instantiated, and then that would be used to call the function. A lot of sources of data are based on the idea of rows and columns.
04:17 Consider databases, spreadsheets, CSV files, and more. When reading and writing to these kinds of data sources, having a row object that knows the name of the columns can be useful.
04:28 Before showing you some code, consider the following CSV file. The first line is a header with the names of the fields, and then there are three lines of data. Each line has a name, title, and email address. Let’s go play with this CSV in the REPL.
04:46
The Python standard library has a handy little module that helps you interact with CSV files. They went out on a limb and named it csv
. Yeah, I know. Crazy, huh? You can never trust those standard-library writers.
04:58 What name will they come up with next?
05:11
Here, I’ve opened the file that has the data I showed you in the previous slide. I’m opening it using a context manager. Once the file is open, the csv_file
variable will contain a file handle.
05:24
The csv
module has several different utility classes. I’m going to use the .reader()
factory, which takes a file handle as an argument.
05:37
The resulting reader
object is an iterable containing the rows of the file as tuples. Because it’s a tuple, I can use a named tuple to make this clearer.
05:56
This part’s a tiny bit tricky. If you haven’t seen next()
before, it’s a built-in function that operates on iterables, returning the next item in the iterable.
06:06
Seeing as I haven’t started iterating on the reader yet, the return value will be the first thing in the iterable. Recall the first row in the file was the header line containing the field names. As the named tuple factory needs a set of names for the fields, this is all rather convenient. By sending the first row of the file to the named tuple factory, I’m creating the Employee
named tuple class with three attributes: .name
, .title
, and .email
. Neat, huh? For safety’s sake, I’m using the optional rename
argument for the named tuple factory.
06:38 Because I’ve set this value, if the CSV file happened to have a field name that wasn’t a legal tuple name, this code would still work. Okay. With the employee class created, I can now start processing the rest of the CSV file.
06:53
I’m going to iterate on the reader in a for
loop.
07:00
Remember that since I called next()
on reader already, this loop will start with the second line in the CSV file.
07:11 For each row, I’m creating an employee instance, and now I’m going to do something with this instance.
07:27 This something in this case is just printing it out. Boring, but functional, makes my point. When it runs, I see each employee object printed out to the screen.
07:38 If all you’re doing is printing it out, the named tuple doesn’t make that much of a difference. But imagine doing a lot of work on this file. Think back to the pen example.
07:46
Wouldn’t it be much better to have a readable employee than having to remember that index 1
is their title? In the next lesson, I’ll walk you through how named tuples compare to other data structures in Python.
Become a Member to join the conversation.