We Back Up

Hey there! Welcome back to the Learn Python with Fantasy Football tutorial series.

A lot of you may know the original series I wrote back in 2020 for Fantasy Football Data Pros, which was quite popular amongst Reddit, and hasn't been updated in a while. We've been spending the last couple months at Fantasy Data Pros creating this new platform that caters to every sport, so there hasn't been a ton of time to deliver new content, which has kind of sucked. Thankfully though, we've also spent some time working on the internal code base of our site to make writing blog posts super easy for us, so now that we're back up we could be delivering content at a faster rate than ever.

This post is an effort to revamp the tutorial series for the 2022 season and on for a couple more seasons (before I have to go back and update everything again).

This tutorial series, at least starting out, is meant for complete beginners. We will eventually work our way to bigger and better things like working with Pandas (a Python library) and doing some machine learning, but we're going to start out this post with the very basics of Python before jumping in to the deep end.

The whole point of this series, and all of our content, is to introduce coding to sports fans in a non-intimidating and easy-to-digest manner.

Additionally, all of our content is focused around project-based learning. I know first hand that project-based learning is the best way to learn to code.

In this post, we'll of course explain what Python is, how we can use it to analyze fantasy football data, and then we'll get into writing some code with a specific and hopefully fun fantasy football project.

Coding Environment

When we're writing code, we need to have an environment to do so. You can't just open a word processor and start banging out lines of code. There needs to be an intermediary software that we use that will help us interact with something that will either "interpret" our code or compile it down to 1's and 0's (Python uses the "interpretation" approach rather than the compilation approach). The topic of interpreation vs. compilation is for another day - what you need to know right now is we need a place to write our code.

There's numerous setups out there we can use. A very popular enviornment we can use is a notebook-based environment such as Jupyter or Google Colab. These environments are (a) very easy for beginners to learn starting out (as opposed to IDEs and even text editors which, in almost all cases, will require you downloading software and making some changes to your computer) and (b) are well-suited for data science projects, as they allow us to interate on datasets very quickly. Text editors are okay for beginners, and they vary on a wide range of complexity for the user to interact with, but we want to keep things even simpler by not even downloading any software. (IDEs, ie. Integrate Development Environments are like text editors, but they come with a lot more packed on. They aren't what I'd recommend for beginners, as they can be complex to work with and they hold your hand through a lot of the learning process).

There's a certain notebook environment that's completely browser-based and wouldn't require any downloads or nasty configuration with your computers. It's called Google Colab.

For the purposes of all our content, we are going to be using this environment for our code. Google is infamous for pulling the rug out from under users in relation to it's products, but for now, we'll stick with Colab. When that day comes it'll be very stressful for me to update all of the content, but hopefully by then you'll be skilled enough to handle other environments :).

Let's Write Some Code!

Let's get in to writing the code.

As I promised above, every bit of our content is focused on a specific project in mind.

In this project, we are going to softly introduce you to some basic programming concepts such as variables and also functions, and using that info we'll be calculating catch rates for various WRs.

Assuming you've been able to get Colab up and running, type in the code below in to the first cell and hit the keystroke combo Shift Enter . Nothing should output but that will "run" your cell. This is how we execute code in a notebook environment. We'll examine this data / object in a second.

players = [
    "name": "Tyreek Hill",
    "catches": 81,
    "targets": 106
    "name": "Stefon Diggs",
    "catches": 72,
    "targets": 99
    "name": "Justin Jefferson",
    "catches": 69, # nice
    "targets": 100

The Main Goal of Programming

So programming is all about moving around and manipulating data, mostly. Now, it’s really easy to move around data when you can save it somewhere and then reference it later.

This is what variables are for. We can set variables to some type of data and then reference that variable later when we want to move around or manipulate that data.

That’s what we’re doing here with the players variable. We could have named our variable anything (or almost anything. There’s certain rules and conventions on how you can name variables), and we set it equal to a list data type.


A list is pretty much what it sounds like – a list of Python “objects”. Lists are enclosed by square brackets on both sides. Python objects that go inside lists can either be integers, floats (don’t worry about this for now), dictionaries, strings (a sentence or bunch of ASCII characters enclosed by double or single quotes), lists themselves (you can have a list of lists), and a lot more. Lists can basically hold any Python object, and also, importantly, the type of those objects does not need to be the same. For example, you can have a list which contains strings, integers, and lists that contain, strings, integers, lists, and so on. You get the point. Each of these items is separated by a comma. Again, if you don’t put square brackets or commas in their right place, you get a SyntaxError .

If this all sounds confusing – it’s okay, over time you learn to think in terms of these “objects”.

Here are some examples of Python lists.

my_list_one = [1,2,3,4]
my_list_two = ['a', 'b', 'c', 'd']
my_list_three = [[1,2,3], [4,5,6]]
my_list_four = [my_list_one, my_list_two, my_list_three]
my_list_five = [1, 'a', my_list_four, { 'key': 'value'}]

That’s a lot of case scenarios, but I just wanted to give you an idea of how flexible lists can be. You don’t need to understand all of this, but try to wrap your head around some of it. You can see that for my_list_four we were able to reference my_list_one , my_list_two , my_list_three . This is one of the powers of using variables, you can reference them later in your code (which we’ll also be doing today).


In my list_five , the last object in our list is what’s know as a dictionary. A dictionary consists of key, value pairs. Dictionaries are enclosed by curly braces. Each key: value pair is separated by a comma just like in lists. So for example, {‘catches’: 100, ‘targets’: 120} . A dictionary is a useful way of organizing a whole column of a players data.

I can literally write for hours on lists and different ways to organize them but this is all you really need to know for right now. If you can absorb all this information, you’re ready to move on to the next part.

Let’s take a look at our list, then. You can probably tell by now that we have a list of dictionaries. Each dictionary has information on an NFL wide receiver – in this case – Tyreek Hill, Stefon Diggs, and Justin Jefferson, the three leading WRs in fantasy this year.

The information for each player is stored in a dictionary, with information on their name, catches, and number of targets.

for loops and iteration

Lists are what’s called iterable (in a way that dictionaries are not). Iterable means we can run a sequence of tasks across the list. We do this with something called a for loop. A for loop basically tells Python – "for every object in the list, run this task on that object"

Now that we’ve gone over the list of dictionaries, let’s go over the for loop that will run a task for each item in the list (each player dictionary)

for player in players:
    name = player['name']
    catches = player['catches']
    targets = player['targets']
    catch_rate = catches/targets
    print(name + ' had a catch rate of ' + str(catch_rate))
Tyreek Hill had a catch rate of 0.7641509433962265
Stefon Diggs had a catch rate of 0.7272727272727273
Justin Jefferson had a catch rate of 0.69

This is the next block of code that comes after our list, so let’s run through this step by step.

Note that the block of code underneath the line for player in players: has to be indented by using tab. Python is pretty strict on this, so if you don’t do this right you’ll get an error again, this time an IndentationError .

We are essentially saying in the first line that for each “player” (our dictionary object) in our players list, run the following code on that player object in the indented block below. Each player object will be a Python dictionary, so we have to run code that manipulates and pulls data from a dictionary.

Dictionaries are really only useful when we want to pull out that value by referencing the key. You can think of our dictionary sort of as a database or excel table in this case scenario that has a bunch of data organized in two columns (Ever used VLOOKUP in excel?).

Here, for each player, we pull out the name value by using player[‘name’] to get our player name. This is the syntax we use to pull values from a dictionary. I’ve alluded to the concept of syntax throughout this post by mentioning SyntaxError . Syntax is essentially a language’s requirements for how to do a certain task or write a certain line of code. Good convention, which we'll talk about in future posts, isn't necessarily syntax. The syntax to pull a value from a Python dictionary is dictionary_name[‘key_name’] .

Remember, the placeholder player is a Python dictionary. We then save our player’s name to a variable we call name so we can reference it later in the code.

We then do the same thing with catches and targets, except this time, after we save our player[‘catches’] and player[‘targets’] to variables we call catches and targets, respectively, we then reference both variables afterwards as well.

We declare a new variable, which we call catch_rate , to catches divided by targets . Both the values we extract from the keys catches and targets are data types known as integers, so we are allowed to do this. We can multiply integers together, divide them, and do all sort of basic arithmetic stuff in Python.

Then, in the final line of our for loop, we use something called a function (twice). Python has a number of “built-in” functions, meaning functions we can use that Python just provides for us. You sometimes have to create functions yourself using def . This is something we’ll be doing in another post and in a lot more detail in the book.

A function takes an input and returns an output. We are using two functions here. Sort of like functions in Excel or high school algebra. There’s one built-in function called print , which takes in a Python object and outputs it back to us below. That’s literally all it does. We’ll be using the print function to tell Python to output each player’s catch rate in a human-readable way.

The other built-in function we’re using is called str , which takes any Python object and converts it to a string.


Python strings are a sequence of characters enclosed in single or double quotes. They are used to store and manipulate text-based data. Strings are immutable, which means they cannot be changed once they are created. They support various operations, such as concatenation, slicing, and indexing, which allow users to manipulate and manipulate strings according to their needs. Strings are commonly used in Python programs to represent text-based data, such as names, addresses, and other alphanumeric data. Below are some examples of strings.

string_one = "This is a string. Hello"
string_two = "1 2 3 4. This is also a string"
string_three = "This is a string, too. We're all strings"
string_four = "This, too, is a 'string'"
string_five = string_one + ' ' + string_two

Just showing you how flexible strings can be. You don’t need to understand all of this right now.

You can actually combine strings together by adding them, like in string_five , and it’ll come out as a single string all put together. The only thing is, that all the objects you are concatenating (that’s the official word for it) must all be strings. This is where the str function becomes handy. Our catch rate is a number (A float, to be specific, but don’t worry about that), but if we want to output a string and concatenate them together, all the objects we are concatenating need to be strings. So we use the str function to be able add all the items together.

Finishing up

That’s pretty much it. Run the code using the keytroke combo Shift Enter and see what outputs. You should see an output identical to the one in the header image.

This is basic stuff, but hopefully you can already start to see the power of programming. It’s actually possible to have a collection of thousands of rows of data like this and be able to “iterate” through them to find the information we just found in seconds. Of course, inputting thousands of rows of data like we did above would be painstaking and monotonous, but that's where data sets come in to play.

If you made it this far, you’re awesome. Hopefully you were able to gain something valuable from this post. If you have any questions, PM on Reddit, email at [email protected], shoot me a DM over Twitter @bendominguez011 or (probably best) leave a comment below.

My suggestion on what to do next is to play around with the code, break it (this is actually important), do some independent research, and maybe expand upon it. Below is a link to the official Python tutorial you may want to check out if this is your first time using Python (Don’t be discouraged if you don’t understand everything in the links below. I still don’t understand everything in the Python documentation 10 or so years later).

Python documentation