How To Use Lists in Python

Lists in Python
(Image credit: Tom's Hardware)

Lists are a common way to store multiple pieces of data in Python. By creating one list we can neatly store many different types of data within it. They work just like a shopping list. We give the list a name, then enter items under the list. 

Lists are another data storage structure, just like dictionaries, tuples and sets. Lists are mutable objects, we can change the contents by updating, deleting and adding to a list. Objects stored in a list come under the broad term of “items” and each item has a position in the list, an index number. The first object in the list has the index number of zero, and as we get more items, it counts up.

We’re going to learn how to create lists and then update and delete the items within them. Then we will apply our knowledge to create a shopping list app which sends lists directly to our cell phone.

To demonstrate how to use lists in Python, we will use Thonny, a free, easy to use and cross platform Python editor. 

Before you begin, install Thonny if you don’t have it already. Go to the Thonny site to download the release for your system. Alternatively, install the official Python release using this guide. Note that this guide covers installation on Windows 10 and 11.

How To Create a List in Python

The most basic form of a list involves creating the list object and then placing items inside of it.

1. In a new blank document, create a list called “shopping” and in there store three items of shopping. Items in a list can be integers, floats, strings, even another list. Lists can also be created with no items, shopping = [] will create a blank list but we will need to append data to it. We cover updating lists later.

shopping = ["Apples","Bananas","Milk"]

2. Print the entire contents of the list. This shows the list contents, including the [ ] brackets.

print(shopping)

3. Save the code as shopping.py and click Run >> Run Current Script. The output looks something like ['Apples', 'Bananas', 'Milk'] which proves that the list works, but we can use it to generate content in sentences.

4. Add another print function to identify that we are printing a shopping list.

print("The shopping list contains")

5. Using a for loop with a range, we print each item from the list, using Python’s string formatting method to drop the item into the sentence as a string. How do we know the number of items in a list to create a range? Well right now it doesn’t matter as the len() function will calculate the length of the shopping list object and use that value as the range. Then the for loop will iterate through the items, updating the value of i each time the loop iterates.

for i in range(len(shopping)):
   print("I need to buy {:s}".format(shopping[i]))

6. Save the code and click Run >> Run Current Script. We will see the full list printed, then our shopping list text is printed to the Python Shell.

Complete Code Listing: Creating a List

shopping = ["Apples","Bananas","Milk"]
print(shopping)
print("The shopping list contains")
for i in range(len(shopping)):
   print("I need to buy {:s}".format(shopping[i]))

Updating and Deleting Items in a List

Lists are mutable objects. This means we can create, update and delete entries from a list. In our current shopping list we have bananas, but we have looked in the fruit bowl and found that we have plenty of bananas, but we have no grapes! So lets swap the bananas for grapes.

1. On a new line outside of the previous for loop, print a message to say that we are updating the contents of the shopping list.

print("Shopping list has changed")

2. Change Bananas to Grapes by updating the value for that item in the list. We know that “Bananas” is the second item in the list, as Python counts from zero we know that the item's position in the list is 1.

shopping[1] = "Grapes"

3. Using a for loop with a range we print each item from the list. This will print out the old list, and then the updated list.

4. Save and run the code. The updated list, and the previous list are printed to the Python Shell.

We open the fridge door and realize that we need to add butter, eggs and cheese to our shopping list. We can append a single item to the end of the list or we can extend the list and pass it multiple items.

1. On a new line outside of the previous for loop and print a message to say that we are updating the contents of the shopping list, again.

print("Shopping list has changed again")

2. Append Cheese to the shopping list. Append will add the item to the end of the list.

shopping.append("Cheese")

3. Use extend to add multiple items to the shopping list. Extend requires us to wrap the items that we wish to add in parenthesis. These new items can be any iterable objects, in this case I have used a tuple to contain the items.

shopping.extend(("Butter","Eggs"))

4. Using a for loop with a range we print each item from the list. This will print out the old lists, and then the updated list.

5. Save and run the code. The updated list, and the previous lists are printed to the Python Shell.

We get to the store and realize that we don’t need eggs! So let's take them off our list.

1. On a new line outside of the previous for loop, print a message to say that we are removing the eggs.

print("Removing the eggs")

2. Remove the eggs from the shopping list. Note that the item value is case sensitive. “Eggs” is not the same as “eggs”.

shopping.remove("Eggs")

3. Use a conditional statement to check that Eggs are no longer on the shopping list. If there are eggs, it will tell us that we forgot to remove them. If there are no eggs, then the else condition will activate and print that they have been removed from the list.

if "Eggs" in shopping:
   print("I forgot to remove the eggs")
else:
   print("The eggs have been removed from the list")

4. Save and run the code. If the eggs have been removed you will see a confirmation, if not, then you will see a reminder.

Complete Code Listing: Updating and Deleting Items in a List

print("Shopping list has changed")
shopping[1] = "Grapes"
for i in range(len(shopping)):
    print("I need to buy {:s}".format(shopping[i]))

print("Shopping list has changed again")
shopping.append("Cheese")
shopping.extend(("Butter","Eggs"))
for i in range(len(shopping)):
    print("I need to buy {:s}".format(shopping[i]))

print("Removing the eggs")
shopping.remove("Eggs")
if "Eggs" in shopping:
    print("I forgot to remove the eggs")
else:
    print("The eggs have been removed from the list")

Using a For Loop With a List

Earlier we used a for loop with a range to print the items in our shopping list using its position (index number). There is another way though, we can create a variable and using a for loop we can iterate over the items in the shopping list and print them out. All of this is accomplished without the need for an index number.

1. On a new line, print a message to say that we are using a for loop.

print("Using a for loop to print our shopping list")

2. Use a for loop to iterate over each item in the shopping list. The value of “item” will change each time the for loop iterates. When all of the items have been iterated through, the for loop will end.

for item in shopping:

3. Print the message to the Python Shell using string formatting. We only need to pass the item variable, not shopping(item) as we are working inside the list.

   print("I need to buy {:s}".format(item))

4. Save and run the code. The for loop will print out the contents of the shopping list.

Complete Code Listing: Using a For Loop With a List

print("Using a for loop to print our shopping list")
for item in shopping:
   print("I need to buy {:s}".format(item))

Using Lists in a Real World Project

(Image credit: Tom's Hardware)

A shopping list on our desktop computer isn’t much use really, but a shopping list on our cell phone, and the cellphones of other family members is. We’re going to use ntfy.sh, a service to send notifications to Android and iOS devices. We used it in our Dictionaries how to as a service to send messages and images to devices.

1. Install ntfy.sh for your Android / iOS device.

2. Open the app and click on + to create a new subscription.

(Image credit: Tom's Hardware)

3. Create a new topic and click Subscribe. We chose to use th-shopping-list. Create a topic that is personal to you. Also note that topics may not be password protected, so do not send sensitive data.

(Image credit: Tom's Hardware)

4. Leave the app open on your device. 

Now our attention turns to our PC running Thonny.

5. Create a blank file.

6. Import the requests module. This is a module of pre-written Python code designed for sending and receiving network connections.

import requests

7. Create a blank list called shopping.

shopping = []

8. Create a variable, num_items and using an input function, capture the answer to the question and save it as an integer. The input function can take a prompt argument, with it we can create custom prompts.

num_items = int(input("How many items do you want to add to your shopping list? "))

9. Using a for loop, iterate through the required number of items, asking the user to enter the item name and append to the shopping list. Another input function is used to capture the users shopping items, the prompt has to be a string for we use f-string formatting to convert. What we convert is the value of i, the item. The value of i is linked to the index number, the item’s position in the list. In the list it starts from zero, but for the input prompt we add one to the value for something that is more understandable for most humans. This is purely cosmetic and does not impact the list index numbers.

for i in range(num_items):
   item = input(f"Enter item {i+1}: ")
   shopping.append(item)

10. Print a message and then use a for loop to print the contents of the shopping list. This is more for debugging, but useful to check that our list is correct.

print("The shopping list is:")
for item in shopping:
   print(item)

11. Create a new variable, shopping_list and in there store the entire contents of the shopping list, using commas to separate the values. This is a formatting step to ensure that the list is sent correctly via ntfy.sh.

shopping_list = (", ".join(shopping))

12. Send the shopping list to the correct ntfy.sh topic. The shopping_list object is the data that we wish to send, the header is a title to clearly identify what the data is.

requests.post("https://ntfy.sh/th-shopping-list",
   data=shopping_list,
   headers={ "Title": "Shopping List" })

13. Save the code as shopping-list.py and click Run. Enter the number of shopping list items, press Enter and type each item and press Enter. Once the final entry has been made, the final Enter key press will send the list to your cellphone / mobile device. Check your device for the notification.

(Image credit: Tom's Hardware)

Complete Code Listing: Real World Project

import requests
shopping = []
num_items = int(input("How many items do you want to add to your shopping list? "))
for i in range(num_items):
   item = input(f"Enter item {i+1}: ")
   shopping.append(item)
print("The shopping list is:")
for item in shopping:
   print(item)
shopping_list = (", ".join(shopping))
requests.post("https://ntfy.sh/th-shopping-list",
   data=shopping_list,
headers={ "Title": "Shopping List" })

More Python Tutorials

Python How Tos

Les Pounder

Les Pounder is an associate editor at Tom's Hardware. He is a creative technologist and for seven years has created projects to educate and inspire minds both young and old. He has worked with the Raspberry Pi Foundation to write and deliver their teacher training program "Picademy".

  • Li Ken-un
    3. Use extend to add multiple items to the shopping list. Extend requires us to wrap the items that we wish to add in parenthesis. These new items can be any iterable objects, in this case I have used a tuple to contain the items.
    shopping.extend(("Butter","Eggs"))
    The first part of the description could use a better explanation. Wrapping the items in parentheses creates a tuple. That’s not a syntactic detail. If you gave it an Iterable instead, wrapping it in parentheses is redundant.

    This code:
    the_list = # Empty list

    the_list.append('First item')

    the_list.extend() # Extending the List with a List literal

    fifth_item_and_sixth_items = ('Fifth item', 'Sixth item') # Assigning a Tuple to a variable

    the_list.extend(fifth_item_and_sixth_items) # Extending the List with a Tuple variable

    seventh_to_ninth_items = # Assigning a List to a variable

    the_list.extend(seventh_to_ninth_items) # Extending the List with a List variable

    the_list.extend(('Tenth item',)) # Extending the List with a Tuple literal containing only one item

    randomly_ordered_set = {'A', 'B', 'C', 1, 2, 3} # Assigning a Set to a variable; items will be unique and unordered

    the_list.extend(randomly_ordered_set)

    sorted_list = sorted(map('Sorted item: {!r}'.format, randomly_ordered_set)) # Assigning a List to a variable created from the randomly ordered set above

    the_list.extend(sorted_list)

    print('The list items:')
    print('\n'.join(map('* {}'.format, the_list)))
    Yields this output (may differ where Sets are used):
    The list items:
    * First item
    * Second item
    * Third item
    * Fourth item
    * Fifth item
    * Sixth item
    * Seventh item
    * Eighth item
    * Ninth item
    * Tenth item
    * A
    * 1
    * 2
    * 3
    * B
    * C
    * Sorted item: 'A'
    * Sorted item: 'B'
    * Sorted item: 'C'
    * Sorted item: 1
    * Sorted item: 2
    * Sorted item: 3
    Reply
  • bit_user
    I think the biggest omission is probably that you can use a list to pass a variable into a function, as a means of pass-by-reference. Here's a quick, hypothetical example:

    num_fruits = 0
    num_vegetables = 0
    num_grains = 0

    for bag in groceries:
    update_counts( bag, num_fruits, num_vegetables, num_grains )
    At the end, all of the counters will still be zero, because any updates the function makes to those parameter values will be local and won't reach the scope of the caller. If you instead passed in a list of counters, then the function could modify the list and the caller would see the modifications.

    The other key thing is to show how to force a copy, when you don't want to simply copy or pass a reference.

    I also think it was a missed opportunity to omit any mention of built-in functions that operate on iterable objects (which includes lists):
    all()
    any()
    enumerate()
    filter()
    map()
    max()
    min()
    sorted()
    sum()
    zip()
    For details, look here: https://docs.python.org/3/library/functions.html
    Reply
  • Li Ken-un
    bit_user said:
    I think the biggest omission is probably that you can use a list to pass a variable into a function, as a means of pass-by-reference.
    This is a behavior of Python I’ve never looked into, but a bit of experimentation yielded some interesting results.

    Everything in Python is actually already passed by reference. 😯
    def function(value):
    print(f'The memory address of the argument is {id(value):x}.')

    letter = 'A'
    number = 1
    mutable_list =
    print(f'The memory address of the letter is {id(letter):x}.')
    print(f'The memory address of mutable_list is {id(mutable_list):x}.')
    function(letter)

    print()

    print(f'The memory address of the number is {id(number):x}.')
    print(f'The memory address of mutable_list is {id(mutable_list):x}.')
    function(number)

    print()

    print(f'The memory address of mutable_list is {id(mutable_list):x}.')
    function(mutable_list)Output:The memory address of the letter is a64740.
    The memory address of mutable_list is a64740.
    The memory address of the argument is a64740.
    The memory address of the number is a59a68.
    The memory address of mutable_list is a59a68.
    The memory address of the argument is a59a68.
    The memory address of mutable_list is 7fa219398e00.
    The memory address of the argument is 7fa219398e00.
    But yea, assigning to the argument isn’t a way to get the result outside the function:
    def arg_mutating_function_1(arg):
    print(f'\tThe memory address of arg in the function is {id(arg):x}.')
    print(f'\tThe value of arg in the function is {arg!r}')
    arg += 1
    print(f'\tThe value of arg in the function is {arg!r}')
    print(f'\tThe memory address of arg in the function is {id(arg):x}.')

    number = 0
    print(f'The memory address of number is {id(number):x}.')
    print(f'The value of number is {number!r}')
    arg_mutating_function_1(number)
    print(f'The value of number is {number!r}')
    print(f'The memory address of number is {id(number):x}.')Output:The memory address of number is a59a48.
    The value of number is 0
    The memory address of arg in the function is a59a48.
    The value of arg in the function is 0
    The value of arg in the function is 1
    The memory address of arg in the function is a59a68.
    The value of number is 0
    The memory address of number is a59a48.
    Putting the variable of interest in a List does allow for it:
    def arg_mutating_function_2(arg):
    print(f'\tThe memory address of arg in the function is {id(arg):x}.')
    print(f'\tThe value of arg in the function is {arg!r}')
    arg += 1
    print(f'\tThe value of arg in the function is {arg!r}')
    print(f'\tThe memory address of arg in the function is {id(arg):x}.')

    number_in_list = print(f'The memory address of number_in_list is {id(number_in_list):x}.')
    print(f'The value of number_in_list is {number_in_list!r}')
    arg_mutating_function_2(number_in_list)
    print(f'The value of number_in_list is {number_in_list!r}')
    print(f'The memory address of number is {id(number_in_list):x}.')Output:The memory address of number_in_list is 7fa21822e7c0.
    The value of number_in_list is The memory address of arg in the function is 7fa21822e7c0.
    The value of arg in the function is The value of arg in the function is The memory address of arg in the function is 7fa21822e7c0.
    The value of number_in_list is The memory address of number is 7fa21822e7c0.
    Wrapping in anything pretty much allows for it as well:
    from dataclasses import dataclass

    @dataclass
    class number_wrapper:
    number: int

    def arg_mutating_function_3(arg):
    print(f'\tThe memory address of arg in the function is {id(arg):x}.')
    print(f'\tThe value of arg in the function is {arg!r}')
    arg.number += 1
    print(f'\tThe value of arg in the function is {arg!r}')
    print(f'\tThe memory address of arg in the function is {id(arg):x}.')

    number_wrapping_instance = number_wrapper(0)
    print(f'The memory address of number_wrapping_instance is {id(number_wrapping_instance):x}.')
    print(f'The value of number_wrapping_instance is {number_wrapping_instance!r}')
    arg_mutating_function_3(number_wrapping_instance)
    print(f'The value of number_wrapping_instance is {number_wrapping_instance!r}')
    print(f'The memory address of number_wrapping_instance is {id(number_wrapping_instance):x}.')Output:The memory address of number_wrapping_instance is 7fa2193fc250.
    The value of number_wrapping_instance is number_wrapper(number=0)
    The memory address of arg in the function is 7fa2193fc250.
    The value of arg in the function is number_wrapper(number=0)
    The value of arg in the function is number_wrapper(number=1)
    The memory address of arg in the function is 7fa2193fc250.
    The value of number_wrapping_instance is number_wrapper(number=1)
    The memory address of number_wrapping_instance is 7fa2193fc250.

    Manipulating arguments this way is sort of like using C♯’s ref or out keywords, but doesn’t feel idiomatic in Python. The most common example of C♯’s ref or out is bool TryParse(string? s, out T result) which returns whether it parsed successfully and assigns the result of type T as a side-effect. In Python, returning a Tuple is the closest idiomatic equivalent. But now that the match statement is available in Python there’s an elegant way to handle the returned Tuple:
    def try_parse(string: str) -> (bool, int):
    try:
    return True, int(string)
    except:
    return False, None

    def test(string: str) -> None:
    match try_parse(string):
    case True, value:
    print(f'Parsed string {string!r} into value {value!r}.')
    case _:
    print(f'Failed to parse string {string!r}.')

    for string in ('123456789', 'lol no', '1.2'):
    test(string)Output:Parsed string '123456789' into value 123456789.
    Failed to parse string 'lol no'.
    Failed to parse string '1.2'.
    Of course the above is a contrived example. It’s idiomatic Python to use exception handling as part of normal control flow. “Easier to ask for forgiveness than permission.”
    bit_user said:
    zip()
    zip is quite the fun function. 😬
    Reply
  • bit_user
    Li Ken-un said:
    This is a behavior of Python I’ve never looked into, but a bit of experimentation yielded some interesting results.
    Thanks for posting your test code. Illustrates some key points.

    Li Ken-un said:
    Everything in Python is actually already passed by reference. 😯
    I meant semantically, not mechanically. Since Python uses garbage collection, it doesn't surprise me if even immutable types are passed by reference.

    Li Ken-un said:
    now that the match statement is available in Python there’s an elegant way to handle the returned Tuple:
    Thanks for the demo. I hadn't heard of match, but then I really don't follow Python, lately.
    Reply