Featured resource
2025 Tech Upskilling Playbook
Tech Upskilling Playbook

Build future-ready tech teams and hit key business milestones with seven proven plays from industry leaders.

Check it out
  • Lab
    • Libraries: If you want this lab, consider one of these libraries.
    • Cloud
Google Cloud Platform icon
Labs

Defining and Using Python Generators

Generators are Python functions that behave like iterators. By using generators, we're able to create sequences that are evaluated as each item is needed, making them more memory-efficient compared to simply having lists. In this hands-on lab, we'll be building a generator function that behaves like the built-in `range` function, except it will yield string characters instead of integers. To feel comfortable completing this lab, you'll need to know how to do the following: * Defining and using generators. Watch the "Defining and Using Generators" video from the Certified Entry-Level Python Programmer Certification course. * Working with `for` loops. Watch the "The `for` Loop" video from the Certified Entry-Level Python Programmer Certification course. * Using the `ord` and `chr` functions. Watch the "String Encodings and Functions" video from the Certified Entry-Level Python Programmer Certification course.

Google Cloud Platform icon
Lab platform
Lab Info
Level
Beginner
Last updated
Aug 29, 2025
Duration
30m

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.
Table of Contents
  1. Challenge

    Create the char_range Generator

    The first thing that we need to create is the char_range function within the using-generators.py file. Just creating a function doesn't make it a generator. To do that, we need to use the keyword yield. Let's create the function and simply yield the start character for the time being:

    using-generators.py (partial)

    def char_range(start, stop, step=1):
        yield start
    

    Now if we run the file, we should make it past the first check that ensures we've created a generator. You should see the following assertion error:

    $ python3.7 using-generators.py
    Traceback (most recent call last):
      File "using-generators.py", line 23, in <module>
        ], f"Expected ['a', 'b', 'c', 'd', 'e'] but got {repr(list(char_range('a', 'e')))}"
    AssertionError: Expected ['a', 'b', 'c', 'd', 'e'] but got ['a']
    

    Next, we'll need to create a range from our starting character to our ending character by utilizing the Unicode code point for each character. To do this we'll use the ord function, and then we'll yield the result of the chr function and the code point for each item in our range. Here's how we might write this:

    using-generators.py (partial)

    def char_range(start, stop, step=1):
        start_code = ord(start)
        stop_code = ord(stop)
    
        for value in range(start_code, stop_code, step):
            yield chr(value)
    

    Now if we run this, we'll see the following error:

    $ python3.7 using-generators.py
    Traceback (most recent call last):
      File "using-generators.py", line 27, in <module>
        ], f"Expected ['a', 'b', 'c', 'd', 'e'] but got {repr(list(char_range('a', 'e')))}"
    AssertionError: Expected ['a', 'b', 'c', 'd', 'e'] but got ['a', 'b', 'c', 'd']
    

    We're creating the range, but we're not yet being inclusive of the stop character.

  2. Challenge

    Include the Stop Character in the Results

    Now that we're yielding characters properly, we need to deviate from how the range function works to also include the stop character's code point. To do this, we'll add 1 to the stop character when we are creating our range:

    using-generators.py (partial)

    def char_range(start, stop, step=1):
        start_code = ord(start)
        stop_code = ord(stop)
    
        for value in range(start_code, stop_code + 1, step):
            yield chr(value)
    

    Now when we run the file we should see the following error:

    $ python3.7 using-generators.py
    Traceback (most recent call last):
      File "using-generators.py", line 37, in <module>
        ], f"Expected ['e', 'd', 'c', 'b', 'a'] but got {repr(list(char_range('e', 'a')))}"
    AssertionError: Expected ['e', 'd', 'c', 'b', 'a'] but got []
    

    This error is caused by us not being able to create a range from a higher number to a lower number while using a positive step value.

  3. Challenge

    Support the Start Code Point Being More Than the Stop Code Point

    To support creating a range from a higher Unicode code point to a lower one, we'll need to make our step value negative if we see that the code point for start is greater than the code point for stop. We can do this by using a conditional and reassigning the step variable:

    using-generators.py (partial)

    def char_range(start, stop, step=1):
        start_code = ord(start)
        stop_code = ord(stop)
    
        if start_code > stop_code:
            step *= -1
    
        for value in range(start_code, stop_code + 1, step):
            yield chr(value)
    

    Running the file again we can see that this almost works:

    $ python3.7 using-generators.py
    Traceback (most recent call last):
      File "using-generators.py", line 40, in <module>
        ], f"Expected ['e', 'd', 'c', 'b', 'a'] but got {repr(list(char_range('e', 'a')))}"
    AssertionError: Expected ['e', 'd', 'c', 'b', 'a'] but got ['e', 'd', 'c']
    

    The issue here is that we're always adding a positive 1 to our stop character's code point — even if we're stepping in a negative direction. To get around this, we can store the value that we add to the stop_code in a variable and make it negative if we need to negate the step value. Here's what this code change looks like:

    using-generators.py (partial)

    def char_range(start, stop, step=1):
        stop_modifier = 1
        start_code = ord(start)
        stop_code = ord(stop)
    
        if start_code > stop_code:
            step *= -1
            stop_modifier *= -1
    
        for value in range(start_code, stop_code + stop_modifier, step):
            yield chr(value)
    

    Now the stop_modifier variable will adjust based on our step direction. Running the file one last time, we should see no output at all, which indicates that char_range meets all of the predefined expectations.

About the author

Pluralsight Skills gives leaders confidence they have the skills needed to execute technology strategy. Technology teams can benchmark expertise across roles, speed up release cycles and build reliable, secure products. By leveraging our expert content, skill assessments and one-of-a-kind analytics, keep up with the pace of change, put the right people on the right projects and boost productivity. It's the most effective path to developing tech skills at scale.

Real skill practice before real-world application

Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.

Learn by doing

Engage hands-on with the tools and technologies you’re learning. You pick the skill, we provide the credentials and environment.

Follow your guide

All labs have detailed instructions and objectives, guiding you through the learning process and ensuring you understand every step.

Turn time into mastery

On average, you retain 75% more of your learning if you take time to practice. Hands-on labs set you up for success to make those skills stick.

Get started with Pluralsight