Build a Dice-Rolling Application With Python

Build a Dice-Rolling Application With Python

by Leodanis Pozo Ramos Jan 19, 2022 basics projects python

Building small projects, like a text-based user interface (TUI) dice-rolling application, will help you level up your Python programming skills. You’ll learn how to gather and validate the user’s input, import code from modules and packages, write functions, use for loops and conditionals, and neatly display output by using strings and the print() function.

In this project, you’ll code an application that simulates dice-rolling events. To do so, you’ll use Python’s random module.

In this tutorial, you’ll learn how to:

  • Use random.randint() to simulate dice-rolling events
  • Ask for the user’s input using the built-in input() function
  • Parse and validate the user’s input
  • Manipulate strings using methods, such as .center() and .join()

You’ll also learn the basics of how to structure, organize, document, and run your Python programs and scripts.

Click the link below to download the entire code for this dice-rolling application and follow along while you build the project yourself:

Demo

In this step-by-step project, you’ll build an application that runs dice-rolling simulations. The app will be able to roll up to six dice, with each die having six faces. After every roll, the application will generate an ASCII diagram of dice faces and display it on the screen. The following video demonstrates how the app works:

Python Dice Roll App Demo Video

When you run your dice-rolling simulator app, you get a prompt asking for the number of dice you want to roll. Once you provide a valid integer from 1 to 6, inclusive, then the application simulates the rolling event and displays a diagram of dice faces on the screen.

Project Overview

Your dice-rolling simulator app will have a minimal yet user-friendly text-based user interface (TUI), which will allow you to specify the number of six-sided dice that you’d like to roll. You’ll use this TUI to roll the dice at home without having to fly to Las Vegas.

Here’s a description of how the app will work internally:

Tasks to Run Tools to Use Code to Write
Prompt the user to choose how many six-sided dice to roll, then read the user’s input Python’s built-in input() function A call to input() with appropriate arguments
Parse and validate the user’s input String methods, comparison operators, and conditional statements A user-defined function called parse_input()
Run the dice-rolling simulation Python’s random module, specifically the randint() function A user-defined function called roll_dice()
Generate an ASCII diagram with the resulting dice faces Loops, list.append(), and str.join() A user-defined function called generate_dice_faces_diagram()
Display the diagram of dice faces on the screen Python’s built-in print() function A call to print() with appropriate arguments

Keeping these internal workings in mind, you’ll code three custom functions to provide the app’s main features and functionalities. These functions will define your code’s public API, which you’ll call to bring the app to life.

To organize the code of your dice-rolling simulator project, you’ll create a single file called dice.py in a directory of your choice in your file system. Go ahead and create the file to get started!

Prerequisites

You should be comfortable with the following concepts and skills before you start building this dice-rolling simulation project:

If you don’t have all of the prerequisite knowledge before starting this coding adventure, then that’s okay! You might learn more by going ahead and getting started! You can always stop and review the resources linked here if you get stuck.

Step 1: Code the TUI of Your Python Dice-Rolling App

In this step, you’ll write the required code to ask for the user’s input of how many dice they want to roll in the simulation. You’ll also code a Python function that takes the user’s input, validates it, and returns it as an integer number if the validation was successful. Otherwise, the function will ask for the user’s input again.

To download the code for this step, click the following link and navigate to the source_code_step_1/ folder:

Take the User’s Input at the Command Line

To get your hands dirty, you can start writing the code that interacts with the user. This code will provide the app’s text-based interface and will rely on input(). This built-in function reads the user input from the command line. Its prompt argument allows you to pass a description of what type of input you need.

Fire up your favorite editor or IDE and type the following code into your dice.py file:

 1# dice.py
 2
 3# ~~~ App's main code block ~~~
 4# 1. Get and validate user's input
 5num_dice_input = input("How many dice do you want to roll? [1-6] ")
 6num_dice = parse_input(num_dice_input)

Your call to input() on line 5 displays a prompt asking how many dice the user wants to roll. The number must fall in the interval from 1 to 6, inclusive, as the prompt suggests.

Line 6 calls parse_input() and stores the return value in num_dice. In the following section, you’ll implement this function.

Parse and Validate the User’s Input

The job of parse_input() is to take the user’s input as a string, check if it’s a valid integer number, and return it as a Python int object. Go ahead and add the following to your dice.py file, right before the app’s main code:

 1# dice.py
 2
 3def parse_input(input_string):
 4    """Return `input_string` as an integer between 1 and 6.
 5
 6    Check if `input_string` is an integer number between 1 and 6.
 7    If so, return an integer with the same value. Otherwise, tell
 8    the user to enter a valid number and quit the program.
 9    """
10    if input_string.strip() in {"1", "2", "3", "4", "5", "6"}:
11        return int(input_string)
12    else:
13        print("Please enter a number from 1 to 6.")
14        raise SystemExit(1)
15
16# ~~~ App's main code block ~~~
17# ...

Here’s how this code works line by line:

  • Line 3 defines parse_input(), which takes the input string as an argument.

  • Lines 4 to 9 provide the function’s docstring. Including an informative and well-formatted docstring in your functions is a best practice in Python programming because docstrings allow you to document your code.

  • Line 10 checks if the user input is a valid value for the number of dice to roll. The call to .strip() removes any unwanted spaces around the input string. The in operator checks if the input falls within the set of allowed numbers of dice to roll. In this case, you use a set because membership tests in this Python data structure are quite efficient.

  • Line 11 converts the input into an integer number and returns it to the caller.

  • Line 13 prints a message to the screen to alert the user of invalid input, if applicable.

  • Line 14 exits the app with a SystemExit exception and a status code of 1 to signal that something went wrong.

With parse_input(), you process and validate the user’s input at the command line. Validating any input that comes directly from the user or any untrusted sources is key for your application to work reliably and securely.

Now that you have a user-friendly TUI and a proper input validation mechanism, you need to make sure that these functionalities work correctly. That’s what you’ll do in the following section.

Try Out the Dice-Rolling App’s TUI

To try out the code that you’ve written so far, open a command-line window and run your dice.py script:

$ python dice.py
How many dice do you want to roll? [1-6] 3

$ python dice.py
How many dice do you want to roll? [1-6] 7
Please enter a number from 1 to 6.

If you enter an integer number from 1 to 6, then the code doesn’t display a message. On the other hand, if the input isn’t a valid integer number or falls outside the target interval, then you get a message telling you that an integer number from 1 to 6 is required.

Up to this point, you’ve successfully written code to request and parse the user’s input at the command line. This code provides the application’s TUI, which is based on the built-in input() function. You’ve also coded a function to validate the user’s input and return it as an integer number. Now, it’s time to roll the dice!

Step 2: Simulate the Rolling of Six-Sided Dice in Python

Your dice-rolling app now provides a TUI to take the user’s input and process it. Great! To continue building the application’s main functionality, you’ll write the roll_dice() function, which will allow you to simulate a dice-rolling event. This function will take the number of dice that the user wants to roll.

Python’s random module from the standard library provides the randint() function, which generates pseudo-random integer numbers in a given interval. You’ll take advantage of this function to simulate rolling dice.

To download the code for this step, click the following link and look inside the source_code_step_2/ folder:

Here’s the code that implements roll_dice():

 1# dice.py
 2import random
 3
 4# ...
 5
 6def roll_dice(num_dice):
 7    """Return a list of integers with length `num_dice`.
 8
 9    Each integer in the returned list is a random number between
10    1 and 6, inclusive.
11    """
12    roll_results = []
13    for _ in range(num_dice):
14        roll = random.randint(1, 6)
15        roll_results.append(roll)
16    return roll_results
17
18# ~~~ App's main code block ~~~
19# ...

In this code snippet, line 2 imports random into your current namespace. This import allows you to access the randint() function later. Here’s a breakdown of the rest of the code:

  • Line 6 defines roll_dice(), which takes an argument representing the number of dice to roll in a given call.

  • Lines 7 to 11 provide the function’s docstring.

  • Line 12 creates an empty list, roll_results, to store the results of the dice-rolling simulation.

  • Line 13 defines a for loop that iterates once for each die that the user wants to roll.

  • Line 14 calls randint() to generate a pseudo-random integer number from 1 to 6, inclusive. This call generates a single number on each iteration. This number represents the result of rolling a six-sided die.

  • Line 15 appends the current die-rolling result in roll_results.

  • Line 16 returns the list of dice-rolling simulation results.

To try out your newly created function, add the following lines of code to the end of your dice.py file:

 1# dice.py
 2# ...
 3
 4# ~~~ App's main code block ~~~
 5# 1. Get and validate user's input
 6num_dice_input = input("How many dice do you want to roll? [1-6] ")
 7num_dice = parse_input(num_dice_input)
 8# 2. Roll the dice
 9roll_results = roll_dice(num_dice)
10
11print(roll_results)  # Remove this line after testing the app

In this code, line 9 calls roll_dice() with num_dice as an argument. Line 11 calls print() to show the result as a list of numbers on your screen. Each number in the list represents the result for a single die. You can remove line 11 after testing your code.

Go ahead and run your app from the command line:

$ python dice.py
How many dice do you want to roll? [1-6] 5
[6, 1, 3, 6, 6]

$ python dice.py
How many dice do you want to roll? [1-6] 2
[2, 6]

The lists of results on your screen will be different because you’re generating your own pseudo-random numbers. In this example, you simulate the rolling of five and two dice, respectively. The value of each die is between 1 and 6 because you’re working with six-sided dice.

Now that you’ve written and tried out the code that simulates a dice-rolling event, it’s time to move on and provide your application with a flashy way to display these results. That’s what you’ll do in the next section.

Step 3: Generate and Display the ASCII Diagram of Dice Faces

At this point, your app already simulates the rolling of several dice and stores the results as a list of numbers. A list of numbers doesn’t look attractive from the user’s perspective, though. You need a fancier output so that your app looks professional.

In this section, you’ll write code to generate a diagram showing the faces of up to six dice. To do this, you’ll create a bit of ASCII art.

Click the link below to download the code for this step so that you can follow along with the project. You’ll find what you need in the source_code_step_3/ folder:

Set Up the Diagram of Dice Faces

Your dice-rolling simulator app needs a way to show the result of rolling the dice. To this end, you’ll use an ASCII diagram of dice faces that’ll show the result of rolling the desired number of six-sided dice. For example, after rolling four dice, the diagram will look something like this:

~~~~~~~~~~~~~~~~~~~ RESULTS ~~~~~~~~~~~~~~~~~~~
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│  ●   ●  │ │         │ │  ●      │ │  ●      │
│         │ │    ●    │ │    ●    │ │         │
│  ●   ●  │ │         │ │      ●  │ │      ●  │
└─────────┘ └─────────┘ └─────────┘ └─────────┘

Each die face in this diagram reflects the value that results from one iteration of the simulation. To start coding the functionality to build this diagram, you need to put together some ASCII art. Get back to your code editor and add the following:

 1# dice.py
 2import random
 3
 4DICE_ART = {
 5    1: (
 6        "┌─────────┐",
 7        "│         │",
 8        "│    ●    │",
 9        "│         │",
10        "└─────────┘",
11    ),
12    2: (
13        "┌─────────┐",
14        "│  ●      │",
15        "│         │",
16        "│      ●  │",
17        "└─────────┘",
18    ),
19    3: (
20        "┌─────────┐",
21        "│  ●      │",
22        "│    ●    │",
23        "│      ●  │",
24        "└─────────┘",
25    ),
26    4: (
27        "┌─────────┐",
28        "│  ●   ●  │",
29        "│         │",
30        "│  ●   ●  │",
31        "└─────────┘",
32    ),
33    5: (
34        "┌─────────┐",
35        "│  ●   ●  │",
36        "│    ●    │",
37        "│  ●   ●  │",
38        "└─────────┘",
39    ),
40    6: (
41        "┌─────────┐",
42        "│  ●   ●  │",
43        "│  ●   ●  │",
44        "│  ●   ●  │",
45        "└─────────┘",
46    ),
47}
48DIE_HEIGHT = len(DICE_ART[1])
49DIE_WIDTH = len(DICE_ART[1][0])
50DIE_FACE_SEPARATOR = " "
51
52# ...

In lines 4 to 47, you draw six dice faces using ASCII characters. You store the faces in DICE_ART, a dictionary that maps each face to its corresponding integer value.

Line 48 defines DIE_HEIGHT, which holds the number of rows a given face will occupy. In this example, each face takes up five rows. Similarly, line 49 defines DIE_WIDTH to hold the number of columns required to draw a die face. In this example, the width is 11 characters.

Finally, line 50 defines DIE_FACE_SEPARATOR, which holds a whitespace character. You’ll use all these constants to generate and display the ASCII diagram of dice faces for your application.

Generate the Diagram of Dice Faces

At this point, you’ve built the ASCII art for each die face. To put these pieces together into a final diagram representing the complete results of the dice-rolling simulation, you’ll write another custom function:

 1# dice.py
 2
 3# ...
 4
 5def generate_dice_faces_diagram(dice_values):
 6    """Return an ASCII diagram of dice faces from `dice_values`.
 7
 8    The string returned contains an ASCII representation of each die.
 9    For example, if `dice_values = [4, 1, 3, 2]` then the string
10    returned looks like this:
11
12    ~~~~~~~~~~~~~~~~~~~ RESULTS ~~~~~~~~~~~~~~~~~~~
13    ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
14    │  ●   ●  │ │         │ │  ●      │ │  ●      │
15    │         │ │    ●    │ │    ●    │ │         │
16    │  ●   ●  │ │         │ │      ●  │ │      ●  │
17    └─────────┘ └─────────┘ └─────────┘ └─────────┘
18    """
19    # Generate a list of dice faces from DICE_ART
20    dice_faces = []
21    for value in dice_values:
22        dice_faces.append(DICE_ART[value])
23
24    # Generate a list containing the dice faces rows
25    dice_faces_rows = []
26    for row_idx in range(DIE_HEIGHT):
27        row_components = []
28        for die in dice_faces:
29            row_components.append(die[row_idx])
30        row_string = DIE_FACE_SEPARATOR.join(row_components)
31        dice_faces_rows.append(row_string)
32
33    # Generate header with the word "RESULTS" centered
34    width = len(dice_faces_rows[0])
35    diagram_header = " RESULTS ".center(width, "~")
36
37    dice_faces_diagram = "\n".join([diagram_header] + dice_faces_rows)
38    return dice_faces_diagram
39
40# ~~~ App's main code block ~~~
41# ...

This function does the following:

  • Line 5 defines generate_dice_faces_diagram() with a single argument called dice_values. This argument will hold the list of dice-rolling integer values that results from calling roll_dice().

  • Lines 6 to 18 provide the function’s docstring.

  • Line 20 creates an empty list called dice_faces to store the dice faces corresponding to the input list of dice values. These dice faces will display in the final ASCII diagram.

  • Line 21 defines a for loop to iterate over the dice values.

  • Line 22 retrieves the die face corresponding to the current die value from DICE_ART and appends it to dice_faces.

  • Line 25 creates an empty list to hold the rows in the final dice faces diagram.

  • Line 26 defines a loop that iterates over indices from 0 to DIE_HEIGHT - 1. Each index represents the index of a given row in the dice faces diagram.

  • Line 27 defines row_components as an empty list to hold portions of the dice faces that will fill a given row.

  • Line 28 starts a nested for loop to iterate over the dice faces.

  • Line 29 stores each row component.

  • Line 30 joins the row components into a final row string, separating individual components with spaces.

  • Line 31 appends each row string to the list holding the rows that’ll shape the final diagram.

  • Line 34 creates a temporary variable to hold the width of the current dice faces diagram.

  • Line 35 creates a header showing the word RESULTS. To do so, it uses str.center() with the diagram’s width and the tilde symbol (~) as arguments.

  • Line 37 generates a string that holds the final dice faces diagram. The line feed character (\n) works as a row separator. The argument to .join() is a list of strings concatenating the diagram header and the strings (rows) that shape the dice faces.

  • Line 38 returns a ready-to-print dice faces diagram to the caller.

Wow! That was a lot! You’ll go back to this code and improve it to make it more manageable in just a bit. Before doing that, though, you’ll want to try out your application, so you need to finish writing its main code block.

Finish Up the App’s Main Code and Roll the Dice

With generate_dice_faces_diagram() in place, you can now finish writing the application’s main code, which will allow you to actually generate and display the diagram of dice faces on your screen. Go ahead and add the following lines of code to the end of dice.py:

 1# dice.py
 2
 3# ...
 4
 5# ~~~ App's main code block ~~~
 6# 1. Get and validate user's input
 7num_dice_input = input("How many dice do you want to roll? [1-6] ")
 8num_dice = parse_input(num_dice_input)
 9# 2. Roll the dice
10roll_results = roll_dice(num_dice)
11# 3. Generate the ASCII diagram of dice faces
12dice_face_diagram = generate_dice_faces_diagram(roll_results)
13# 4. Display the diagram
14print(f"\n{dice_face_diagram}")

Line 12 calls generate_dice_faces_diagram() with roll_results as an argument. This call builds and returns a diagram of dice faces that corresponds to the current dice-rolling results. Line 14 calls print() to display the diagram on the screen.

With this update, you can run the application again. Get back to your command line and execute the following command:

$ python dice.py
How many dice do you want to roll? [1-6] 5

~~~~~~~~~~~~~~~~~~~~~~~~~ RESULTS ~~~~~~~~~~~~~~~~~~~~~~~~~
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│  ●   ●  │ │  ●   ●  │ │  ●   ●  │ │  ●      │ │  ●   ●  │
│    ●    │ │  ●   ●  │ │  ●   ●  │ │    ●    │ │         │
│  ●   ●  │ │  ●   ●  │ │  ●   ●  │ │      ●  │ │  ●   ●  │
└─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘

Cool! Now your dice-rolling simulator app displays a nicely formatted ASCII diagram showing the result of the simulation event. That’s neat, isn’t it?

If you go back to the implementation of generate_dice_faces_diagram(), then you’ll note that it includes a few comments that point out what the corresponding portion of code is doing:

def generate_dice_faces_diagram(dice_values):
    # ...
    # Generate a list of dice faces from DICE_ART
    dice_faces = []
    for value in dice_values:
        dice_faces.append(DICE_ART[value])

    # Generate a list containing the dice faces rows
    dice_faces_rows = []
    for row_idx in range(DIE_HEIGHT):
        row_components = []
        for die in dice_faces:
            row_components.append(die[row_idx])
        row_string = DIE_FACE_SEPARATOR.join(row_components)
        dice_faces_rows.append(row_string)

    # Generate header with the word "RESULTS" centered
    width = len(dice_faces_rows[0])
    diagram_header = " RESULTS ".center(width, "~")

    dice_faces_diagram = "\n".join([diagram_header] + dice_faces_rows)
    return dice_faces_diagram

This kind of comment often signals that your code would benefit from some refactoring. In the following section, you’ll use a popular refactoring technique that will help you clean up the code and make it more maintainable.

Step 4: Refactor the Code That Generates the Diagram of Dice Faces

Your generate_dice_faces_diagram() function requires explanatory comments because it performs several operations at a time, which violates the single-responsibility principle.

Roughly stated, this principle says that every function, class, or module should do only one thing. That way, changes in a given functionality won’t break the rest of the code. As a result, you’ll end up with a more robust and maintainable code.

To download the code for this step, click the link below, then check out the source_code_step_4/ folder:

There’s a refactoring technique called extract method that can help you improve your code by extracting functionality that can work independently. For example, you can extract the code from line 20 to 22 in the previous implementation of generate_dice_faces_diagram() and place it in a non-public helper function called _get_dice_faces():

def _get_dice_faces(dice_values):
    dice_faces = []
    for value in dice_values:
        dice_faces.append(DICE_ART[value])
    return dice_faces

You can call _get_dice_faces() from generate_dice_faces_diagram() to get the implied functionality. By using this technique, you can fully refactor generate_dice_faces_diagram() to satisfy the single-responsibility principle.

Here’s a refactored version of generate_dice_faces_diagram() that takes advantage of _get_dice_faces() and implements another helper function called _generate_dice_faces_rows() to extract the functionality from line 25 to 31:

# dice.py

# ...

def generate_dice_faces_diagram(dice_values):
    """Return an ASCII diagram of dice faces from `dice_values`.

    The string returned contains an ASCII representation of each die.
    For example, if `dice_values = [4, 1, 3, 2]` then the string
    returned looks like this:

    ~~~~~~~~~~~~~~~~~~~ RESULTS ~~~~~~~~~~~~~~~~~~~
    ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
    │  ●   ●  │ │         │ │  ●      │ │  ●      │
    │         │ │    ●    │ │    ●    │ │         │
    │  ●   ●  │ │         │ │      ●  │ │      ●  │
    └─────────┘ └─────────┘ └─────────┘ └─────────┘
    """
    dice_faces = _get_dice_faces(dice_values)
    dice_faces_rows = _generate_dice_faces_rows(dice_faces)

    # Generate header with the word "RESULTS" centered
    width = len(dice_faces_rows[0])
    diagram_header = " RESULTS ".center(width, "~")

    dice_faces_diagram = "\n".join([diagram_header] + dice_faces_rows)
    return dice_faces_diagram

def _get_dice_faces(dice_values):
    dice_faces = []
    for value in dice_values:
        dice_faces.append(DICE_ART[value])
    return dice_faces

def _generate_dice_faces_rows(dice_faces):
    dice_faces_rows = []
    for row_idx in range(DIE_HEIGHT):
        row_components = []
        for die in dice_faces:
            row_components.append(die[row_idx])
        row_string = DIE_FACE_SEPARATOR.join(row_components)
        dice_faces_rows.append(row_string)
    return dice_faces_rows

# ~~~ App's main code block ~~~
# ...

The newly added helper functions extract functionality from the original function. Now each helper function has its own single responsibility. Helper functions also allow you to use readable and descriptive names, removing the need for explanatory comments.

Refactoring your code to get it into better shape is a great skill to have as a Python developer. To dig deeper into code refactoring, check out Refactoring Python Applications for Simplicity.

A fundamental idea behind code refactoring is that the modified code should work the same as the original code. To check this principle, go ahead and run your application again!

With that, you’ve completed your project! You’ve built a fully functional TUI application that allows you to simulate a dice-rolling event. Every time you run the application, you can simulate the rolling of up to six dice with six faces each. You’ll even get to see the resulting dice faces in a nice-looking ASCII diagram. Great job!

Conclusion

You’ve coded a fully functional project consisting of a text-based user interface application that simulates the rolling of six-sided dice in Python. With this project, you learned and practiced fundamental skills, such as gathering and validating the user’s input, importing code, writing functions, using loops and conditionals, and displaying nicely formatted output on-screen.

In this tutorial, you learned how to:

  • Use random.randint() to simulate the rolling of dice
  • Take the user’s input at the command line using the built-in input() function
  • Parse and validate the user’s input using several tools and techniques
  • Manipulate strings using methods, such as .center() and .join()

Additionally, you learned how to structure, organize, document, and run Python programs and scripts. With this knowledge, you’re better prepared to continue your coding journey with Python.

You can download the full code for this dice-rolling application by clicking the link below:

Next Steps

Now that you’ve finished building your dice-rolling application, you can take the project a step further by adding new functionality. Adding new features by yourself will help you continue to learn exciting new coding concepts and techniques.

Here are some ideas to take your project to the next level:

  • Support for any number of dice: Modify the code so that you can roll any number of dice.
  • Support for dice with different numbers of faces: Add code to support not only six-sided dice but dice with any number of sides.

The first feature will require you to modify the code that processes the user’s input for the number of dice to roll. You’ll also need to modify the code that generates and displays the diagram of dice faces. For example, you can generate a diagram that displays the dice faces in several rows to avoid cluttering your screen with cramped output.

On the other hand, supporting dice with a different number of faces will demand that you tweak the code that simulates a dice-rolling event. You’ll also need to create new ASCII art for any dice with more than six faces.

Once you’re done with these new features, you can change gears and jump into other cool projects. Here are some great next steps for you to continue learning Python and building more complex projects:

🐍 Python Tricks 💌

Get a short & sweet Python Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team.

Python Tricks Dictionary Merge

About Leodanis Pozo Ramos

Leodanis Pozo Ramos Leodanis Pozo Ramos

Leodanis is an industrial engineer who loves Python and software development. He's a self-taught Python developer with 6+ years of experience. He's an avid technical writer with a growing number of articles published on Real Python and other sites.

» More about Leodanis

Each tutorial at Real Python is created by a team of developers so that it meets our high quality standards. The team members who worked on this tutorial are:

Master Real-World Python Skills With Unlimited Access to Real Python

Join us and get access to hundreds of tutorials, hands-on video courses, and a community of expert Pythonistas:

Level Up Your Python Skills »

Master Real-World Python Skills
With Unlimited Access to Real Python

Join us and get access to hundreds of tutorials, hands-on video courses, and a community of expert Pythonistas:

Level Up Your Python Skills »

What Do You Think?

Real Python Comment Policy: The most useful comments are those written with the goal of learning from or helping out other readers—after reading the whole article and all the earlier comments. Complaints and insults generally won’t make the cut here.

What’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know.

Keep Learning

Related Tutorial Categories: basics projects python