You are on page 1of 28

Beginner's Python

Lists (cont.) Dictionaries


List comprehensions Dictionaries store connections between pieces of
information. Each item in a dictionary is a key-value pair.

Cheat Sheet
squares = [x**2 for x in range(1, 11)]
A simple dictionary
Slicing a list
alien = {'color': 'green', 'points': 5}
finishers = ['sam', 'bob', 'ada', 'bea']
first_two = finishers[:2] Accessing a value
Variables and Strings
Copying a list print(f"The alien's color is {alien['color']}.")
Variables are used to assign labels to values. A string is a
series of characters, surrounded by single or double quotes. copy_of_bikes = bikes[:] Adding a new key-value pair
Python's f-strings allow you to use variables inside strings to
alien['x_position'] = 0
build dynamic messages.
Tuples
Hello world Looping through all key-value pairs
Tuples are similar to lists, but the items in a tuple can't be
print("Hello world!") modified. fav_numbers = {'eric': 7, 'ever': 4, 'erin': 47}

Hello world with a variable Making a tuple for name, number in fav_numbers.items():
dimensions = (1920, 1080) print(f"{name} loves {number}.")
msg = "Hello world!"
print(msg) resolutions = ('720p', '1080p', '4K')
Looping through all keys
f-strings (using variables in strings) If statements fav_numbers = {'eric': 7, 'ever': 4, 'erin': 47}
first_name = 'albert' If statements are used to test for particular conditions and for name in fav_numbers.keys():
last_name = 'einstein' respond appropriately. print(f"{name} loves a number.")
full_name = f"{first_name} {last_name}"
print(full_name) Conditional tests Looping through all the values
equal x == 42
fav_numbers = {'eric': 7, 'ever': 4, 'erin': 47}
Lists not equal x != 42
A list stores a series of items in a particular order. You greater than x > 42
for number in fav_numbers.values():
or equal to x >= 42
access items using an index, or within a loop. print(f"{number} is a favorite.")
less than x < 42
Make a list or equal to x <= 42
User input
bikes = ['trek', 'redline', 'giant'] Conditional tests with lists Your programs can prompt the user for input. All input is
Get the first item in a list 'trek' in bikes stored as a string.
'surly' not in bikes
first_bike = bikes[0] Prompting for a value
Assigning boolean values name = input("What's your name? ")
Get the last item in a list
game_active = True print(f"Hello, {name}!")
last_bike = bikes[-1]
can_edit = False
Prompting for numerical input
Looping through a list
A simple if test age = input("How old are you? ")
for bike in bikes: age = int(age)
if age >= 18:
print(bike)
print("You can vote!")
Adding items to a list pi = input("What's the value of pi? ")
If-elif-else statements pi = float(pi)
bikes = []
if age < 4:
bikes.append('trek')
ticket_price = 0
bikes.append('redline')
bikes.append('giant')
elif age < 18:
ticket_price = 10 Python Crash Course
Making numerical lists elif age < 65: A Hands-on, Project-Based
ticket_price = 40 Introduction to Programming
squares = [] else:
for x in range(1, 11): ticket_price = 15 ehmatthes.github.io/pcc_3e
squares.append(x**2)
While loops Classes Working with files
A while loop repeats a block of code as long as a certain A class defines the behavior of an object and the kind of Your programs can read from files and write to files.
condition is true. While loops are especially useful when you information an object can store. The information in a class The pathlib library makes it easier to work with files and
can't know ahead of time how many times a loop should run. is stored in attributes, and functions that belong to a class directories. Once you have a path defined, you can work
are called methods. A child class inherits the attributes and with the read_text() and write_text() methods.
A simple while loop
methods from its parent class.
current_value = 1
Reading the contents of a file
while current_value <= 5: Creating a dog class The read_text() method reads in the entire contents of a file. You
can then split the text into a list of individual lines, and then process
print(current_value) class Dog: each line as you need to.
current_value += 1 """Represent a dog."""
from pathlib import Path
Letting the user choose when to quit def __init__(self, name):
msg = '' """Initialize dog object.""" path = Path('siddhartha.txt')
while msg != 'quit': self.name = name contents = path.read_text()
msg = input("What's your message? ") lines = contents.splitlines()
def sit(self):
if msg != 'quit': """Simulate sitting.""" for line in lines:
print(msg) print(f"{self.name} is sitting.") print(line)

my_dog = Dog('Peso')
Writing to a file
Functions
path = Path('journal.txt')
Functions are named blocks of code, designed to do one print(f"{my_dog.name} is a great dog!")
specific job. Information passed to a function is called an my_dog.sit() msg = "I love programming.")
argument, and information received by a function is called a path.write_text(msg)
parameter. Inheritance
A simple function class SARDog(Dog): Exceptions
"""Represent a search dog."""
def greet_user(): Exceptions help you respond appropriately to errors that are
"""Display a simple greeting.""" def __init__(self, name): likely to occur. You place code that might cause an error in
print("Hello!") """Initialize the sardog.""" the try block. Code that should run in response to an error
super().__init__(name) goes in the except block. Code that should run only if the try
greet_user() block was successful goes in the else block.
Passing an argument def search(self): Catching an exception
"""Simulate searching."""
def greet_user(username): print(f"{self.name} is searching.") prompt = "How many tickets do you need? "
"""Display a personalized greeting.""" num_tickets = input(prompt)
print(f"Hello, {username}!") my_dog = SARDog('Willie')
try:
greet_user('jesse') print(f"{my_dog.name} is a search dog.") num_tickets = int(num_tickets)
my_dog.sit() except ValueError:
Default values for parameters my_dog.search() print("Please try again.")
def make_pizza(topping='pineapple'): else:
"""Make a single-topping pizza.""" print("Your tickets are printing.")
Infinite Skills
print(f"Have a {topping} pizza!")
If you had infinite programming skills, what would you build?
Zen of Python
make_pizza() As you're learning to program, it's helpful to think Simple is better than complex
make_pizza('mushroom') about the real-world projects you'd like to create. It's a
If you have a choice between a simple and a complex
Returning a value good habit to keep an "ideas" notebook that you can
solution, and both work, use the simple solution. Your
refer to whenever you want to start a new project.
def add_numbers(x, y): code will be easier to maintain, and it will be easier
"""Add two numbers and return the sum.""" If you haven't done so already, take a few minutes
for you and others to build on that code later on.
return x + y and describe three projects you'd like to create. As
you're learning you can write small programs that
sum = add_numbers(3, 5) relate to these ideas, so you can get practice writing Weekly posts about all things Python
print(sum) code relevant to topics you're interested in. mostlypython.substack.com
Beginner's Python
Adding elements Sorting a list
You can add elements to the end of a list, or you can insert The sort() method changes the order of a list permanently.
them wherever you like in a list. This allows you to modify The sorted() function returns a copy of the list, leaving the

Cheat Sheet - Lists existing lists, or start with an empty list and then add items to
it as the program develops.
Adding an element to the end of the list
original list unchanged.
You can sort the items in a list in alphabetical order, or
reverse alphabetical order. You can also reverse the original
order of the list. Keep in mind that lowercase and uppercase
What are lists? users.append('amy') letters may affect the sort order.
A list stores a series of items in a particular order. Lists Starting with an empty list Sorting a list permanently
allow you to store sets of information in one place, users = [] users.sort()
whether you have just a few items or millions of items. users.append('amy')
Lists are one of Python's most powerful features users.append('val') Sorting a list permanently in reverse alphabetical order
readily accessible to new programmers, and they tie users.append('bob') users.sort(reverse=True)
together many important concepts in programming. users.append('mia')
Sorting a list temporarily
Inserting elements at a particular position
Defining a list print(sorted(users))
users.insert(0, 'joe') print(sorted(users, reverse=True))
Use square brackets to define a list, and use commas to users.insert(3, 'bea')
separate individual items in the list. Use plural names for Reversing the order of a list
lists, to make it clear that the variable represents more than
one item. Removing elements users.reverse()
You can remove elements by their position in a list, or by the
Making a list value of the item. If you remove an item by its value, Python Looping through a list
users = ['val', 'bob', 'mia', 'ron', 'ned'] removes only the first item that has that value. Lists can contain millions of items, so Python provides an
Deleting an element by its position efficient way to loop through all the items in a list. When
Accessing elements you set up a loop, Python pulls each item from the list one
del users[-1] at a time and assigns it to a temporary variable, which
Individual elements in a list are accessed according to their
position, called the index. The index of the first element is 0, Removing an item by its value you provide a name for. This name should be the singular
the index of the second element is 1, and so forth. Negative version of the list name.
users.remove('mia') The indented block of code makes up the body of the
indices refer to items at the end of the list. To get a particular
element, write the name of the list and then the index of the loop, where you can work with each individual item. Any
element in square brackets. Popping elements lines that are not indented run after the loop is completed.
If you want to work with an element that you're removing Printing all items in a list
Getting the first element from the list, you can "pop" the item. If you think of the list as
first_user = users[0] a stack of items, pop() takes an item off the top of the stack. for user in users:
By default pop() returns the last element in the list, but print(user)
Getting the second element you can also pop elements from any position in the list. Printing a message for each item, and a separate
second_user = users[1] message afterwards
Pop the last item from a list
Getting the last element most_recent_user = users.pop() for user in users:
newest_user = users[-1] print(most_recent_user) print(f"\nWelcome, {user}!")
print("We're so glad you joined!")
Pop the first item in a list
Modifying individual items first_user = users.pop(0) print("\nWelcome, we're glad to see you all!")
Once you've defined a list, you can change the value of print(first_user)
individual elements in the list. You do this by referring to the
index of the item you want to modify.
List length
Changing an element The len() function returns the number of items in a list. Python Crash Course
users[0] = 'valerie' A Hands-on, Project-Based
Find the length of a list
users[1] = 'robert' Introduction to Programming
users[-2] = 'ronald' num_users = len(users)
print(f"We have {num_users} users.") ehmatthes.github.io/pcc_3e
The range() function Copying a list Tuples
You can use the range() function to work with a set of To copy a list make a slice that starts at the first item and A tuple is like a list, except you can't change the values
numbers efficiently. The range() function starts at 0 by ends at the last item. If you try to copy a list without using in a tuple once it's defined. Tuples are good for storing
default, and stops one number below the number passed to this approach, whatever you do to the copied list will affect information that shouldn't be changed throughout the life of a
it. You can use the list() function to efficiently generate a the original list as well. program. Tuples are usually designated by parentheses.
large list of numbers. You can overwrite an entire tuple, but you can't change
Making a copy of a list
the values of individual elements.
Printing the numbers 0 to 1000 finishers = ['kai', 'abe', 'ada', 'gus', 'zoe']
for number in range(1001): copy_of_finishers = finishers[:] Defining a tuple
print(number) dimensions = (800, 600)
Printing the numbers 1 to 1000 List comprehensions Looping through a tuple
You can use a loop to generate a list based on a range of
for number in range(1, 1001): for dimension in dimensions:
numbers or on another list. This is a common operation,
print(number) print(dimension)
so Python offers a more efficient way to do it. List
Making a list of numbers from 1 to a million comprehensions may look complicated at first; if so, use Overwriting a tuple
the for loop approach until you're ready to start using
numbers = list(range(1, 1_000_001)) dimensions = (800, 600)
comprehensions.
print(dimensions)
To write a comprehension, define an expression for the
Simple statistics values you want to store in the list. Then write a for loop to dimensions = (1200, 900)
There are a number of simple statistical operations you can generate input values needed to make the list. print(dimensions)
run on a list containing numerical data.
Using a loop to generate a list of square numbers
Finding the minimum value in a list squares = [] Visualizing your code
ages = [93, 99, 66, 17, 85, 1, 35, 82, 2, 77] for x in range(1, 11): When you're first learning about data structures such as
youngest = min(ages) square = x**2 lists, it helps to visualize how Python is working with the
squares.append(square) information in your program. Python Tutor is a great tool for
Finding the maximum value seeing how Python keeps track of the information in a list.
Using a comprehension to generate a list of square
ages = [93, 99, 66, 17, 85, 1, 35, 82, 2, 77] Try running the following code on pythontutor.com, and then
oldest = max(ages) numbers run your own code.
squares = [x**2 for x in range(1, 11)]
Finding the sum of all values Build a list and print the items in the list
ages = [93, 99, 66, 17, 85, 1, 35, 82, 2, 77] Using a loop to convert a list of names to upper case dogs = []
total_years = sum(ages) names = ['kai', 'abe', 'ada', 'gus', 'zoe'] dogs.append('willie')
dogs.append('hootz')
Slicing a list upper_names = [] dogs.append('peso')
for name in names: dogs.append('goblin')
You can work with any subset of elements from a list. A
upper_names.append(name.upper())
portion of a list is called a slice. To slice a list start with the for dog in dogs:
index of the first item you want, then add a colon and the Using a comprehension to convert a list of names to print(f"Hello {dog}!")
index after the last item you want. Leave off the first index upper case print("I love these dogs!")
to start at the beginning of the list, and leave off the second
index to slice through the end of the list. names = ['kai', 'abe', 'ada', 'gus', 'zoe']
print("\nThese were my first two dogs:")
old_dogs = dogs[:2]
Getting the first three items upper_names = [name.upper() for name in names]
for old_dog in old_dogs:
finishers = ['kai', 'abe', 'ada', 'gus', 'zoe'] print(old_dog)
first_three = finishers[:3] Styling your code
Readability counts del dogs[0]
Getting the middle three items dogs.remove('peso')
middle_three = finishers[1:4] Follow common Python formatting conventions: print(dogs)
• Use four spaces per indentation level.
Getting the last three items • Keep your lines to 79 characters or fewer.
last_three = finishers[-3:] • Use single blank lines to group parts of your
program visually. Weekly posts about all things Python
mostlypython.substack.com
Beginner's Python
Adding new key-value pairs Looping through a dictionary
You can store as many key-value pairs as you want in a You can loop through a dictionary in three ways: you can
dictionary, until your computer runs out of memory. To add a loop through all the key-value pairs, all the keys, or all the

Cheat Sheet - new key-value pair to an existing dictionary give the name of
the dictionary and the new key in square brackets, and set it
equal to the new value.
values.
Dictionaries keep track of the order in which key-value
pairs are added. If you want to process the information in a

Dictionaries
This also allows you to start with an empty dictionary and different order, you can sort the keys in your loop, using the
add key-value pairs as they become relevant. sorted() function.
Adding a key-value pair Looping through all key-value pairs
What are dictionaries? alien_0 = {'color': 'green', 'points': 5} # Store people's favorite languages.
fav_languages = {
Python's dictionaries allow you to connect pieces of alien_0['x'] = 0 'jen': 'python',
related information. Each piece of information in a alien_0['y'] = 25 'sarah': 'c',
dictionary is stored as a key-value pair. When you alien_0['speed'] = 1.5 'edward': 'ruby',
provide a key, Python returns the value associated 'phil': 'python',
Starting with an empty dictionary }
with that key. You can loop through all the key-value
alien_0 = {}
pairs, all the keys, or all the values. # Show each person's favorite language.
alien_0['color'] = 'green'
alien_0['points'] = 5 for name, language in fav_languages.items():
Defining a dictionary print(f"{name}: {language}")
Use curly braces to define a dictionary. Use colons to
connect keys and values, and use commas to separate
Modifying values Looping through all the keys
individual key-value pairs. You can modify the value associated with any key in a # Show everyone who's taken the survey.
dictionary. To do so give the name of the dictionary and the for name in fav_languages.keys():
Making a dictionary key in square brackets, then provide the new value for that print(name)
alien_0 = {'color': 'green', 'points': 5} key.
Looping through all the values
Modifying values in a dictionary
Accessing values alien_0 = {'color': 'green', 'points': 5}
# Show all the languages that have been chosen.
for language in fav_languages.values():
To access the value associated with an individual key give print(alien_0) print(language)
the name of the dictionary and then place the key in a set
of square brackets. If the key you provided is not in the # Change the alien's color and point value. Looping through all the keys in reverse order
dictionary, an error will occur. alien_0['color'] = 'yellow'
# Show each person's favorite language,
You can also use the get() method, which returns alien_0['points'] = 10
# in reverse order by the person's name.
None instead of an error if the key doesn't exist. You can print(alien_0)
for name in sorted(fav_languages.keys(),
also specify a default value to use if the key is not in the reverse=True):
dictionary. Removing key-value pairs language = fav_languages[name]
Getting the value associated with a key You can remove any key-value pair you want from a print(f"{name}: {language}")
dictionary. To do this use the del keyword and the dictionary
alien_0 = {'color': 'green', 'points': 5}
name, followed by the key in square brackets. This will Dictionary length
print(alien_0['color']) delete the key and its associated value. You can find the number of key-value pairs in a dictionary
print(alien_0['points']) Deleting a key-value pair using the len() function.
Getting the value with get() alien_0 = {'color': 'green', 'points': 5} Finding a dictionary's length
print(alien_0) num_responses = len(fav_languages)
alien_0 = {'color': 'green'}
del alien_0['points']
alien_color = alien_0.get('color')
alien_points = alien_0.get('points', 0)
print(alien_0)
Python Crash Course
alien_speed = alien_0.get('speed') A Hands-on, Project-Based
Visualizing dictionaries
print(alien_color) Introduction to Programming
Try running some of these examples on pythontutor.com,
print(alien_points) and then run one of your own programs that uses ehmatthes.github.io/pcc_3e
print(alien_speed) dictionaries.
Nesting - A list of dictionaries Nesting - Lists in a dictionary Dictionary Comprehensions
It's sometimes useful to store a number of dictionaries in a Storing a list inside a dictionary allows you to associate more A comprehension is a compact way of generating a
list; this is called nesting. than one value with each key. dictionary, similar to a list comprehension. To make a
dictionary comprehension, define an expression for the
Storing dictionaries in a list Storing lists in a dictionary
key-value pairs you want to make. Then write a for loop to
# Start with an empty list. # Store multiple languages for each person. generate the values that will feed into this expression.
users = [] fav_languages = { The zip() function matches each item in one list to each
'jen': ['python', 'ruby'], item in a second list. It can be used to make a dictionary
# Make a new user, and add them to the list. 'sarah': ['c'], from two lists.
new_user = { 'edward': ['ruby', 'go'],
'last': 'fermi', 'phil': ['python', 'haskell'], Using a loop to make a dictionary
'first': 'enrico', } squares = {}
'username': 'efermi', for x in range(5):
} # Show all responses for each person. squares[x] = x**2
users.append(new_user) for name, langs in fav_languages.items():
print(f"{name}: ") Using a dictionary comprehension
# Make another new user, and add them as well. for lang in langs:
squares = {x:x**2 for x in range(5)}
new_user = { print(f"- {lang}")
'last': 'curie', Using zip() to make a dictionary
'first': 'marie', Nesting - A dictionary of dictionaries
'username': 'mcurie', group_1 = ['kai', 'abe', 'ada', 'gus', 'zoe']
} You can store a dictionary inside another dictionary. In this group_2 = ['jen', 'eva', 'dan', 'isa', 'meg']
users.append(new_user) case each value associated with a key is itself a dictionary.
pairings = {name:name_2
Storing dictionaries in a dictionary for name, name_2 in zip(group_1, group_2)}
# Show all information about each user.
print("User summary:") users = {
for user_dict in users: 'aeinstein': { Generating a million dictionaries
for k, v in user_dict.items(): 'first': 'albert',
You can use a loop to generate a large number of
print(f"{k}: {v}") 'last': 'einstein',
'location': 'princeton', dictionaries efficiently, if all the dictionaries start out with
print("\n") similar data.
},
You can also define a list of dictionaries directly, A million aliens
without using append(): 'mcurie': {
'first': 'marie', aliens = []
# Define a list of users, where each user 'last': 'curie',
# is represented by a dictionary. 'location': 'paris', # Make a million green aliens, worth 5 points
users = [ }, # each. Have them all start in one row.
{ } for alien_num in range(1_000_000):
'last': 'fermi', new_alien = {
'first': 'enrico', for username, user_dict in users.items(): 'color': 'green',
'username': 'efermi', full_name = f"{user_dict['first']} " 'points': 5,
}, full_name += user_dict['last'] 'x': 20 * alien_num,
{ 'y': 0
'last': 'curie', location = user_dict['location'] }
'first': 'marie',
'username': 'mcurie', print(f"\nUsername: {username}") aliens.append(new_alien)
}, print(f"\tFull name: {full_name.title()}")
] print(f"\tLocation: {location.title()}") # Prove the list contains a million aliens.
num_aliens = len(aliens)
# Show all information about each user.
print("User summary:") Levels of nesting print("Number of aliens created:")
for user_dict in users: Nesting is extremely useful in certain situations. However, print(num_aliens)
for k, v in user_dict.items(): be aware of making your code overly complex. If you're
print(f"{k}: {v}") nesting items much deeper than what you see here there
print("\n") are probably simpler ways of managing your data, such as Weekly posts about all things Python
using classes. mostlypython.substack.com
Beginner's Python
Numerical comparisons If statements
Testing numerical values is similar to testing string values. Several kinds of if statements exist. Your choice of which to
use depends on the number of conditions you need to test.
Testing equality and inequality
Cheat Sheet - >>> age = 18
>>> age == 18
You can have as many elif blocks as you need, and the
else block is always optional.
Simple if statement

If Statements
True
>>> age != 18 age = 19
False

and While Loops


if age >= 18:
Comparison operators print("You're old enough to vote!")
>>> age = 19
>>> age < 21 If-else statements
True age = 17
What are if statements? What are while >>> age <= 21
loops? True if age >= 18:
>>> age > 21 print("You're old enough to vote!")
Python's if statements allow you to examine the False else:
current state of a program and respond appropriately >>> age >= 21 print("You can't vote yet.")
to that state. You can write a simple if statement that False
checks one condition, or you can create a complex The if-elif-else chain
series of statements that identify the exact conditions Checking multiple conditions age = 12
you're interested in. You can check multiple conditions at the same time. The and
while loops run as long as certain conditions operator returns True if all the conditions listed are true. The if age < 4:
price = 0
remain true. You can use while loops to let your or operator returns True if any condition is true.
elif age < 18:
programs run as long as your users want them to. Using and to check multiple conditions price = 25
else:
Conditional Tests >>> age_0 = 22
price = 40
>>> age_1 = 18
A conditional test is an expression that can be evaluated
>>> age_0 >= 21 and age_1 >= 21
as true or false. Python uses the values True and False print(f"Your cost is ${price}.")
False
to decide whether the code in an if statement should be >>> age_1 = 23
executed. >>> age_0 >= 21 and age_1 >= 21 Conditional tests with lists
Checking for equality True You can easily test whether a certain value is in a list. You
A single equal sign assigns a value to a variable. A double equal can also test whether a list is empty before trying to loop
Using or to check multiple conditions
sign checks whether two values are equal. through the list.
If your conditional tests aren't doing what you expect them to, >>> age_0 = 22
make sure you're not accidentally using a single equal sign. >>> age_1 = 18 Testing if a value is in a list
>>> car = 'bmw' >>> age_0 >= 21 or age_1 >= 21 >>> players = ['al', 'bea', 'cyn', 'dale']
>>> car == 'bmw' True >>> 'al' in players
True >>> age_0 = 18 True
>>> car = 'audi' >>> age_0 >= 21 or age_1 >= 21 >>> 'eric' in players
>>> car == 'bmw' False False
False Testing if two values are in a list
Boolean values
Ignoring case when making a comparison >>> 'al' in players and 'cyn' in players
A boolean value is either True or False. Variables with
>>> car = 'Audi' boolean values are often used to keep track of certain
>>> car.lower() == 'audi'
True
conditions within a program.
Simple boolean values
Python Crash Course
Checking for inequality A Hands-on, Project-Based
game_active = True Introduction to Programming
>>> topping = 'mushrooms' is_valid = True
>>> topping != 'anchovies' can_edit = False ehmatthes.github.io/pcc_3e
True
Conditional tests with lists (cont.) While loops (cont.) While loops (cont.)
Testing if a value is not in a list Letting the user choose when to quit Using continue in a loop
banned_users = ['ann', 'chad', 'dee'] prompt = "\nTell me something, and I'll " banned_users = ['eve', 'fred', 'gary', 'helen']
user = 'erin' prompt += "repeat it back to you."
prompt += "\nEnter 'quit' to end the program. " prompt = "\nAdd a player to your team."
if user not in banned_users: prompt += "\nEnter 'quit' when you're done. "
print("You can play!") message = ""
while message != 'quit': players = []
Checking if a list is empty message = input(prompt) while True:
An empty list evaluates as False in an if statement. player = input(prompt)
players = [] if message != 'quit':
print(message) if player == 'quit':
if players: break
Using a flag elif player in banned_users:
for player in players:
Flags are most useful in long-running programs where code from print(f"{player} is banned!")
print(f"Player: {player.title()}")
other parts of the program might need to end the loop. continue
else:
print("We have no players yet!") prompt = "\nTell me something, and I'll " else:
prompt += "repeat it back to you." players.append(player)
prompt += "\nEnter 'quit' to end the program. "
Accepting input print("\nYour team:")
You can allow your users to enter input using the input() active = True for player in players:
function. All input is initially stored as a string. If you want to while active: print(player)
accept numerical input, you'll need to convert the input string message = input(prompt)
value to a numerical type. Avoiding infinite loops
Simple input if message == 'quit':
Every while loop needs a way to stop running so it won't
active = False
name = input("What's your name? ") else: continue to run forever. If there's no way for the condition
print(f"Hello, {name}.") print(message) to become false, the loop will never stop running. You can
usually press Ctrl-C to stop an infinite loop.
Accepting numerical input using int() Using break to exit a loop
An infinite loop
age = input("How old are you? ") prompt = "\nWhat cities have you visited?"
age = int(age) while True:
prompt += "\nEnter 'quit' when you're done. "
name = input("\nWho are you? ")
if age >= 18: print(f"Nice to meet you, {name}!")
while True:
print("\nYou can vote!") city = input(prompt)
else: Removing all instances of a value from a list
print("\nSorry, you can't vote yet.") if city == 'quit': The remove() method removes a specific value from a
break list, but it only removes the first instance of the value you
Accepting numerical input using float() else: provide. You can use a while loop to remove all instances of
tip = input("How much do you want to tip? ") print(f"I've been to {city}!") a particular value.
tip = float(tip)
print(f"Tipped ${tip}.") Removing all cats from a list of pets
Accepting input with Sublime Text
Sublime Text, and a number of other text editors can't run pets = ['dog', 'cat', 'dog', 'fish', 'cat',
While loops programs that prompt the user for input. You can use these 'rabbit', 'cat']
A while loop repeats a block of code as long as a condition editors to write programs that prompt for input, but you'll print(pets)
is true. need to run them from a terminal.
while 'cat' in pets:
Counting to 5 pets.remove('cat')
Breaking out of loops
current_number = 1
You can use the break statement and the continue print(pets)
while current_number <= 5: statement with any of Python's loops. For example you can
print(current_number) use break to quit a for loop that's working through a list or a
current_number += 1 dictionary. You can use continue to skip over certain items Weekly posts about all things Python
when looping through a list or dictionary as well. mostlypython.substack.com
Beginner's Python
Positional and keyword arguments Return values
The two main kinds of arguments are positional and keyword A function can return a value or a set of values. When a
arguments. When you use positional arguments Python function returns a value, the calling line should provide

Cheat Sheet - matches the first argument in the function call with the first
parameter in the function definition, and so forth.
With keyword arguments, you specify which parameter
a variable which the return value can be assigned to. A
function stops running when it reaches a return statement.
Returning a single value

Functions
each argument should be assigned to in the function
call. When you use keyword arguments, the order of the def get_full_name(first, last):
arguments doesn't matter. """Return a neatly formatted full name."""
full_name = f"{first} {last}"
Using positional arguments return full_name.title()
What are functions?
def describe_pet(animal, name):
Functions are named blocks of code designed to do """Display information about a pet.""" musician = get_full_name('jimi', 'hendrix')
one specific job. Functions allow you to write code print(f"\nI have a {animal}.") print(musician)
once that can then be run whenever you need to print(f"Its name is {name}.")
Returning a dictionary
accomplish the same task.
describe_pet('hamster', 'harry') def build_person(first, last):
Functions can take in the information they need,
describe_pet('dog', 'willie') """Return a dictionary of information
and return the information they generate. Using about a person.
functions effectively makes your programs easier to Using keyword arguments """
write, read, test, and maintain. def describe_pet(animal, name): person = {'first': first, 'last': last}
"""Display information about a pet.""" return person
Defining a function print(f"\nI have a {animal}.")
The first line of a function is its definition, marked by the print(f"Its name is {name}.") musician = build_person('jimi', 'hendrix')
keyword def. The name of the function is followed by a set print(musician)
of parentheses and a colon. A docstring, in triple quotes, describe_pet(animal='hamster', name='harry')
Returning a dictionary with optional values
describes what the function does. The body of a function is describe_pet(name='willie', animal='dog')
indented one level. def build_person(first, last, age=None):
Default values """Return a dictionary of information
To call a function, give the name of the function followed
about a person.
by a set of parentheses. You can provide a default value for a parameter. When """
Making a function function calls omit this argument the default value will be person = {'first': first, 'last': last}
used. Parameters with default values must be listed after if age:
def greet_user(): parameters without default values in the function's definition person['age'] = age
"""Display a simple greeting.""" so positional arguments can still work correctly.
print("Hello!")
Using a default value return person
greet_user() def describe_pet(name, animal='dog'): musician = build_person('jimi', 'hendrix', 27)
"""Display information about a pet.""" print(musician)
Passing information to a function print(f"\nI have a {animal}.")
Information that's passed to a function is called an argument; print(f"Its name is {name}.") musician = build_person('janis', 'joplin')
information that's received by a function is called a print(musician)
parameter. Arguments are included in parentheses after the describe_pet('harry', 'hamster')
describe_pet('willie')
function's name, and parameters are listed in parentheses in Visualizing functions
the function's definition. Using None to make an argument optional Try running some of these examples, and some of your own
Passing a simple argument def describe_pet(animal, name=None): programs that use functions, on pythontutor.com.
def greet_user(username): """Display information about a pet."""
print(f"\nI have a {animal}.")
"""Display a simple greeting."""
print(f"Hello, {username}!") if name: Python Crash Course
print(f"Its name is {name}.")
A Hands-on, Project-Based
greet_user('jesse') Introduction to Programming
greet_user('diana') describe_pet('hamster', 'harry')
greet_user('brandon') describe_pet('snake') ehmatthes.github.io/pcc_3e
Passing a list to a function Passing an arbitrary number of arguments Modules
You can pass a list as an argument to a function, and the Sometimes you won't know how many arguments a function You can store your functions in a separate file called a
function can work with the values in the list. Any changes the will need to accept. Python allows you to collect an arbitrary module, and then import the functions you need into the
function makes to the list will affect the original list. You can number of arguments into one parameter using the * file containing your main program. This allows for cleaner
prevent a function from modifying a list by passing a copy of operator. A parameter that accepts an arbitrary number of program files. Make sure your module is stored in the same
the list as an argument. arguments must come last in the function definition. This directory as your main program.
parameter is often named *args.
Passing a list as an argument Storing a function in a module
The ** operator allows a parameter to collect an arbitrary
File: pizza.py
def greet_users(names): number of keyword arguments. These are stored as a
"""Print a simple greeting to everyone.""" dictionary with the parameter names as keys, and the def make_pizza(size, *toppings):
for name in names: arguments as values. This is often named **kwargs. """Make a pizza."""
msg = f"Hello, {name}!" print(f"\nMaking a {size} pizza.")
print(msg) Collecting an arbitrary number of arguments print("Toppings:")
def make_pizza(size, *toppings): for topping in toppings:
usernames = ['hannah', 'ty', 'margot'] """Make a pizza.""" print(f"- {topping}")
greet_users(usernames) print(f"\nMaking a {size} pizza.")
Importing an entire module
Allowing a function to modify a list File: making_pizzas.py Every function in the module is available in
print("Toppings:")
The following example sends a list of models to a function for the program file.
printing. The first list is emptied, and the second list is filled.
for topping in toppings:
print(f"- {topping}") import pizza
def print_models(unprinted, printed):
"""3d print a set of models.""" # Make three pizzas with different toppings. pizza.make_pizza('medium', 'pepperoni')
while unprinted: make_pizza('small', 'pepperoni') pizza.make_pizza('small', 'bacon', 'pineapple')
current_model = unprinted.pop() make_pizza('large', 'bacon bits', 'pineapple')
print(f"Printing {current_model}") make_pizza('medium', 'mushrooms', 'peppers', Importing a specific function
printed.append(current_model) 'onions', 'extra cheese') Only the imported functions are available in the program file.
from pizza import make_pizza
# Store some unprinted designs, Collecting an arbitrary number of keyword arguments
# and print each of them. def build_profile(first, last, **user_info): make_pizza('medium', 'pepperoni')
unprinted = ['phone case', 'pendant', 'ring'] """Build a dictionary for a user.""" make_pizza('small', 'bacon', 'pineapple')
printed = [] user_info['first'] = first
print_models(unprinted, printed) user_info['last'] = last Giving a module an alias
import pizza as p
print(f"\nUnprinted: {unprinted}") return user_info
print(f"Printed: {printed}") p.make_pizza('medium', 'pepperoni')
Preventing a function from modifying a list # Create two users with different kinds p.make_pizza('small', 'bacon', 'pineapple')
# of information.
The following example is the same as the previous one, except the Giving a function an alias
original list is unchanged after calling print_models().
user_0 = build_profile('albert', 'einstein',
location='princeton') from pizza import make_pizza as mp
def print_models(unprinted, printed):
"""3d print a set of models.""" user_1 = build_profile('marie', 'curie', mp('medium', 'pepperoni')
while unprinted: location='paris', field='chemistry') mp('small', 'bacon', 'pineapple')
current_model = unprinted.pop()
print(f"Printing {current_model}") print(user_0) Importing all functions from a module
printed.append(current_model) print(user_1) Don't do this, but recognize it when you see it in others' code. It can
result in naming conflicts, which can cause errors.
# Store some unprinted designs,
# and print each of them.
What's the best way to structure a function? from pizza import *
original = ['phone case', 'pendant', 'ring'] There are many ways to write and call a function. When
printed = [] you're starting out, aim for something that simply works. As make_pizza('medium', 'pepperoni')
you gain experience you'll develop an understanding of the make_pizza('small', 'bacon', 'pineapple')
print_models(original[:], printed) subtle advantages of different structures such as positional
print(f"\nOriginal: {original}") and keyword arguments, and the various approaches to
print(f"Printed: {printed}") importing functions. For now if your functions do what you Weekly posts about all things Python
need them to, you're doing well. mostlypython.substack.com
Beginner's Python
Creating and using a class (cont.) Class inheritance
Creating an instance from a class If the class you're writing is a specialized version of another
class, you can use inheritance. When one class inherits

Cheat Sheet - Classes


my_car = Car('audi', 'a4', 2021)
from another, it automatically takes on all the attributes
Accessing attribute values and methods of the parent class. The child class is free
to introduce new attributes and methods, and override
print(my_car.make)
attributes and methods of the parent class.
print(my_car.model)
What are classes? print(my_car.year)
To inherit from another class include the name of the
parent class in parentheses when defining the new class.
Classes are the foundation of object-oriented
Calling methods The __init__() method for a child class
programming. Classes represent real-world things
you want to model in your programs such as dogs, my_car.fill_tank() class ElectricCar(Car):
cars, and robots. You use a class to make objects, my_car.drive() """A simple model of an electric car."""
which are specific instances of dogs, cars, and robots. Creating multiple instances
A class defines the general behavior that a whole def __init__(self, make, model, year):
my_car = Car('audi', 'a4', 2024) """Initialize an electric car."""
category of objects can have, and the information that my_old_car = Car('subaru', 'outback', 2018) super().__init__(make, model, year)
can be associated with those objects. my_truck = Car('toyota', 'tacoma', 2020)
Classes can inherit from each other—you can write my_old_truck = Car('ford', 'ranger', 1999) # Attributes specific to electric cars.
a class that extends the functionality of an existing # Battery capacity in kWh.
class. This allows you to code efficiently for a wide Modifying attributes self.battery_size = 40
variety of situations. Even if you don't write many You can modify an attribute's value directly, or you can
# Charge level in %.
of your own classes, you'll frequently find yourself write methods that manage updating values more carefully.
self.charge_level = 0
working with classes that others have written. Methods like these can help validate the kinds of changes
that are being made to an attribute. Adding new methods to the child class
Creating and using a class Modifying an attribute directly class ElectricCar(Car):
Consider how we might model a car. What information would --snip--
my_new_car = Car('audi', 'a4', 2024)
we associate with a car, and what behavior would it have?
my_new_car.fuel_level = 5
The information is assigned to variables called attributes, def charge(self):
and the behavior is represented by functions. Functions that Writing a method to update an attribute's value """Fully charge the vehicle."""
are part of a class are called methods. self.charge_level = 100
def update_fuel_level(self, new_level):
print("The vehicle is fully charged.")
The Car class """Update the fuel level."""
if new_level <= self.fuel_capacity: Using child methods and parent methods
class Car:
self.fuel_level = new_level
"""A simple attempt to model a car.""" my_ecar = ElectricCar('nissan', 'leaf', 2024)
else:
print("The tank can't hold that much!")
def __init__(self, make, model, year): my_ecar.charge()
"""Initialize car attributes.""" Writing a method to increment an attribute's value my_ecar.drive()
self.make = make
self.model = model def add_fuel(self, amount):
self.year = year """Add fuel to the tank.""" Finding your workflow
if (self.fuel_level + amount There are many ways to model real world objects and
# Fuel capacity and level in gallons. <= self.fuel_capacity): situations in code, and sometimes that variety can feel
self.fuel_capacity = 15 self.fuel_level += amount overwhelming. Pick an approach and try it; if your first
self.fuel_level = 0 print("Added fuel.") attempt doesn't work, try a different approach.
else:
def fill_tank(self): print("The tank won't hold that much.")
"""Fill gas tank to capacity."""
self.fuel_level = self.fuel_capacity Naming conventions Python Crash Course
print("Fuel tank is full.") In Python class names are usually written in CamelCase A Hands-on, Project-Based
and object names are written in lowercase with underscores. Introduction to Programming
def drive(self): Modules that contain classes should be named in lowercase
"""Simulate driving.""" with underscores. ehmatthes.github.io/pcc_3e
print("The car is moving.")
Class inheritance (cont.) Importing classes Storing objects in a list
Overriding parent methods Class files can get long as you add detailed information and A list can hold as many items as you want, so you can make
functionality. To help keep your program files uncluttered, a large number of objects from a class and store them in a
class ElectricCar(Car):
you can store your classes in modules and import the list.
--snip--
classes you need into your main program. Here's an example showing how to make a fleet of rental
cars, and make sure all the cars are ready to drive.
def fill_tank(self): Storing classes in a file
"""Display an error message.""" car.py A fleet of rental cars
print("This car has no fuel tank!")
"""Represent gas and electric cars.""" from car import Car, ElectricCar

Instances as attributes class Car: # Make lists to hold a fleet of cars.


A class can have objects as attributes. This allows classes to """A simple attempt to model a car.""" gas_fleet = []
work together to model more complex real-world things and --snip— electric_fleet = []
concepts.
class Battery: # Make 250 gas cars and 500 electric cars.
A Battery class """A battery for an electric car.""" for _ in range(250):
class Battery: --snip-- car = Car('ford', 'escape', 2024)
"""A battery for an electric car.""" gas_fleet.append(car)
class ElectricCar(Car): for _ in range(500):
def __init__(self, size=85): """A simple model of an electric car.""" ecar = ElectricCar('nissan', 'leaf', 2024)
"""Initialize battery attributes.""" --snip-- electric_fleet.append(ecar)
# Capacity in kWh, charge level in %.
Importing individual classes from a module # Fill the gas cars, and charge electric cars.
self.size = size
my_cars.py for car in gas_fleet:
self.charge_level = 0
from car import Car, ElectricCar car.fill_tank()
def get_range(self): for ecar in electric_fleet:
"""Return the battery's range.""" my_beetle = Car('volkswagen', 'beetle', 2021) ecar.charge()
if self.size == 40: my_beetle.fill_tank()
return 150 my_beetle.drive() print(f"Gas cars: {len(gas_fleet)}")
elif self.size == 65: print(f"Electric cars: {len(electric_fleet)}")
return 225 my_leaf = ElectricCar('nissan', 'leaf', 2024)
Using an instance as an attribute
my_leaf.charge() Understanding self
my_leaf.drive()
People often ask what the self variable represents. The
class ElectricCar(Car): self variable is a reference to an object that's been created
--snip--
Importing an entire module
from the class.
import car The self variable provides a way to make other variables
def __init__(self, make, model, year):
and objects available everywhere in a class. The self
"""Initialize an electric car.""" my_beetle = car.Car(
variable is automatically passed to each method that's
super().__init__(make, model, year) 'volkswagen', 'beetle', 2021)
my_beetle.fill_tank() called through an object, which is why you see it listed first
# Attribute specific to electric cars. my_beetle.drive() in most method definitions. Any variable attached to self is
self.battery = Battery() available everywhere in the class.
my_leaf = car.ElectricCar('nissan', 'leaf',
def charge(self): 2024) Understanding __init__()
"""Fully charge the vehicle.""" my_leaf.charge() The __init__() method is a function that's part of a class,
self.battery.charge_level = 100 my_leaf.drive() just like any other method. The only special thing about
print("The vehicle is fully charged.") __init__() is that it's called automatically every time
Importing all classes from a module
Using the instance (Don’t do this, but recognize it when you see it.) you make a new instance from a class. If you accidentally
misspell __init__(), the method won't be called and your
my_ecar = ElectricCar('nissan', 'leaf', 2024) from car import * object may not be created correctly.
my_ecar.charge() my_beetle = Car('volkswagen', 'beetle', 2021)
print(my_ecar.battery.get_range()) my_leaf = ElectricCar('nissan', 'leaf', 2024)
my_ecar.drive() Weekly posts about all things Python
mostlypython.substack.com
Beginner's Python
Writing to a file Path objects (cont.)
The write_text() method can be used to write text to a Build a path
file. Be careful, this will write over the current file if it already

Cheat Sheet -
base_path = Path("/Users/eric/text_files")
exists. To append to a file, read the contents first and then
file_path = base_path / "alice.txt"
rewrite the entire file.
Writing to a file Check if a file exists

Files and Exceptions from pathlib import Path >>> path = Path("text_files/alice.txt")
>>> path.exists()
True
path = Path("programming.txt")
Why work with files? Why use exceptions? msg = "I love programming!"
Get filetype
Your programs can read information in from files, and path.write_text(msg) >>> path.suffix
they can write data to files. Reading from files allows '.txt'
Writing multiple lines to a file
you to work with a wide variety of information; writing
to files allows users to pick up where they left off the from pathlib import Path The try-except block
next time they run your program. You can write text to When you think an error may occur, you can write a try-
path = Path("programming.txt") except block to handle the exception that might be raised.
files, and you can store Python structures such as lists
in data files as well. The try block tells Python to try running some code, and the
msg = "I love programming!" except block tells Python what to do if the code results in a
Exceptions are special objects that help your msg += "\nI love making games."
particular kind of error.
programs respond to errors in appropriate ways. path.write_text(msg)
For example if your program tries to open a file that Handling the ZeroDivisionError exception
Appending to a file
doesn’t exist, you can use exceptions to display an try:
from pathlib import Path print(5/0)
informative error message instead of having the
program crash. except ZeroDivisionError:
path = Path("programming.txt") print("You can't divide by zero!")
contents = path.read_text()
Reading from a file Handling the FileNotFoundError exception
To read from a file your program needs to specify the contents += "\nI love programming!"
from pathlib import Path
path to the file, and then read the contents of the file. The contents += "\nI love making games."
read_text() method returns a string containing the entire path.write_text(contents)
path = Path("siddhartha.txt")
contents of the file. try:
Reading an entire file at once Path objects contents = path.read_text()
The pathlib module makes it easier to work with files in except FileNotFoundError:
from pathlib import Path msg = f"Can’t find file: {path.name}."
Python. A Path object represents a file or directory, and lets
you carry out common directory and file operations. print(msg)
path = Path('siddhartha.txt')
contents = path.read_text() With a relative path, Python usually looks for a location
relative to the .py file that's running. Absolute paths are Knowing which exception to handle
print(contents) relative to your system's root folder ("/"). It can be hard to know what kind of exception to handle
Windows uses backslashes when displaying file paths, but when writing code. Try writing your code without a try block,
Working with a file's lines you should use forward slashes in your Python code. and make it generate an error. The traceback will tell you
It's often useful to work with individual lines from a file. Once the
Relative path what kind of exception your program needs to handle. It's a
contents of a file have been read, you can get the lines using the
splitlines() method.
good idea to skim through the exceptions listed at
path = Path("text_files/alice.txt") docs.python.org/3/library/exceptions.html.
from pathlib import Path Absolute path
path = Path('siddhartha.txt')
contents = path.read_text()
path = Path("/Users/eric/text_files/alice.txt")
Python Crash Course
Get just the filename from a path A Hands-on, Project-Based
lines = contents.splitlines()
>>> path = Path("text_files/alice.txt") Introduction to Programming
for line in lines: >>> path.name ehmatthes.github.io/pcc_3e
print(line) 'alice.txt'
The else block Failing silently Storing data with json
The try block should only contain code that may cause Sometimes you want your program to just continue running The json module allows you to dump simple Python data
an error. Any code that depends on the try block running when it encounters an error, without reporting the error to the structures into a file, and load the data from that file the next
successfully should be placed in the else block. user. Using the pass statement in an except block allows time the program runs. The JSON data format is not specific
you to do this. to Python, so you can share this kind of data with people
Using an else block
who work in other languages as well.
print("Enter two numbers. I'll divide them.")
Using the pass statement in an except block
Knowing how to manage exceptions is important when
from pathlib import Path working with stored data. You'll usually want to make sure
x = input("First number: ") the data you're trying to load exists before working with it.
y = input("Second number: ") f_names = ['alice.txt', 'siddhartha.txt',
'moby_dick.txt', 'little_women.txt'] Using json.dumps() to store data
try: from pathlib import Path
result = int(x) / int(y) for f_name in f_names: import json
except ZeroDivisionError: # Report the length of each file found.
print("You can't divide by zero!") path = Path(f_name) numbers = [2, 3, 5, 7, 11, 13]
else: try:
print(result) contents = path.read_text() path = Path("numbers.json")
except FileNotFoundError: contents = json.dumps(numbers)
Preventing crashes caused by user input pass path.write_text(contents)
Without the except block in the following example, the program else:
would crash if the user tries to divide by zero. As written, it will lines = contents.splitlines() Using json.loads() to read data
handle the error gracefully and keep running. msg = f"{f_name} has {len(lines)}" from pathlib import Path
"""A simple calculator for division only.""" msg += " lines." import json
print(msg)
print("Enter two numbers. I'll divide them.") path = Path("numbers.json")
print("Enter 'q' to quit.") Avoid bare except blocks contents = path.read_text()
Exception handling code should catch specific exceptions numbers = json.loads(contents)
while True: that you expect to happen during your program's execution.
x = input("\nFirst number: ") print(numbers)
A bare except block will catch all exceptions, including
if x == 'q':
keyboard interrupts and system exits you might need when Making sure the stored data exists
break
forcing a program to close.
If you want to use a try block and you're not sure from pathlib import Path
y = input("Second number: ") import json
if y == 'q': which exception to catch, use Exception. It will catch
break most exceptions, but still allow you to interrupt programs
path = Path("numbers.json")
intentionally.
try: Don't use bare except blocks try:
result = int(x) / int(y) contents = path.read_text()
except ZeroDivisionError: try:
except FileNotFoundError:
print("You can't divide by zero!") # Do something
msg = f"Can't find file: {path}"
else: except:
print(msg)
print(result) pass
else:
Use Exception instead numbers = json.loads(contents)
Deciding which errors to report print(numbers)
try:
Well-written, properly tested code is not very prone to # Do something
internal errors such as syntax or logical errors. But every except Exception: Practice with exceptions
time your program depends on something external such as pass Take a program you've already written that prompts for user
user input or the existence of a file, there's a possibility of an input, and add some error-handling code to the program.
exception being raised. Printing the exception Run your program with appropriate and inappropriate data,
It's up to you how to communicate errors to your try: and make sure it handles each situation correctly.
users. Sometimes users need to know if a file is missing; # Do something
sometimes it's better to handle the error silently. A little except Exception as e:
experience will help you know how much to report. print(e, type(e)) Weekly posts about all things Python
mostlypython.substack.com
Beginner's Python
Installing pytest A failing test (cont.)
Installing pytest with pip Running the test
When you change your code, it’s important to run your existing

Cheat Sheet -
$ python -m pip install --user pytest
tests. This will tell you whether the changes you made affect existing
behavior.
Testing a function (cont.) $ pytest

Testing Your Code Building a testcase with one unit test


To build a test case, import the function you want to test. Any
functions that begin with test_ will be run by pytest. Save this file
============= test session starts =============
test_full_names_failing.py F [100%]

as test_full_names.py. ================== FAILURES ===================


Why test your code? from full_names import get_full_name _______________ test_first_last _______________
> full_name = get_full_name('janis',
When you write a function or a class, you can also 'joplin')
write tests for that code. Testing proves that your code def test_first_last():
"""Test names like Janis Joplin.""" E TypeError: get_full_name() missing 1
works as it's supposed to in the situations it's designed full_name = get_full_name('janis', required positional argument: 'last'
to handle, and also when people use your programs in 'joplin')
unexpected ways. Writing tests gives you confidence assert full_name == 'Janis Joplin' =========== short test summary info ===========
that your code will work correctly as more people FAILED test_full_names.py::test_first_last...
Running the test
begin to use your programs. You can also add new ============== 1 failed in 0.04s ==============
Issuing the pytest command tells pytest to run any file beginning
features to your programs and know whether or not with test_. pytest reports on each test in the test case.
you've broken existing behavior by running your tests. The dot after test_full_names.py represents a single passing test. Fixing the code
A unit test verifies that one specific aspect of your pytest informs us that it ran 1 test in about 0.01 seconds, and that When a test fails, the code needs to be modified until the test
the test passed. passes again. Don’t make the mistake of rewriting your tests to fit
code works as it's supposed to. A test case is a your new code, otherwise your code will break for anyone who's
collection of unit tests which verify that your code's $ pytest using it the same way it's being used in the failing test.
behavior is correct in a wide variety of situations. ============= test session starts ============= Here we can make the middle name optional:
The output in some sections has been trimmed for platform darwin -- Python 3.11.0, pytest-7.1.2
rootdir: /.../testing_your_code def get_full_name(first, last, middle=''):
space. collected 1 item """Return a full name."""

Testing a function: a passing test test_full_names.py . [100%] if middle:


The pytest library provides tools for testing your code. To ============== 1 passed in 0.01s ============== full_name = f"{first} {middle} {last}"
try it out, we’ll create a function that returns a full name. We’ll else:
full_name = f"{first} {last}"
use the function in a regular program, and then build a test Testing a function: A failing test
case for the function.
Failing tests are important; they tell you that a change in the return full_name.title()
A function to test code has affected existing behavior. When a test fails, you
Save this as full_names.py need to modify the code so the existing behavior still works. Running the test
Now the test should pass again, which means our original
def get_full_name(first, last): Modifying the function functionality is still intact.
"""Return a full name.""" We’ll modify get_full_name() so it handles middle names, but
$ pytest
we’ll do it in a way that breaks existing behavior.
full_name = f"{first} {last}" ============= test session starts =============
return full_name.title() def get_full_name(first, middle, last): test_full_names.py . [100%]
"""Return a full name."""
Using the function full_name = f"{first} {middle} {last}" ============== 1 passed in 0.01s ==============
Save this as names.py return full_name.title()
from full_names import get_full_name Using the function

janis = get_full_name('janis', 'joplin')


print(janis)
from full_names import get_full_name
Python Crash Course
john = get_full_name('john', 'lee', 'hooker') A Hands-on, Project-Based
print(john) Introduction to Programming
bob = get_full_name('bob', 'dylan')
print(bob) ehmatthes.github.io/pcc_3e
david = get_full_name('david', 'lee', 'roth')
print(david)
Adding new tests Testing a class Using fixtures
You can add as many unit tests to a test case as you need. Testing a class is similar to testing a function, since you’ll A fixture is a resource that's used in multiple tests. When the
To write a new test, add a new function to your test file. If the mostly be testing its methods. name of a fixture function is used as an argument to a test
file grows too long, you can add as many files as you need. function, the return value of the fixture is passed to the test
A class to test
function.
Testing middle names Save as account.py
When testing a class, you often have to make an instance
We’ve shown that get_full_name() works for first and last names.
class Account(): of the class. Fixtures let you work with just one instance.
Let’s test that it works for middle names as well.
"""Manage a bank account."""
from full_names import get_full_name Using fixtures to support multiple tests
def __init__(self, balance=0): The instance acc can be used in each new test.
def test_first_last(): """Set the initial balance.""" import pytest
"""Test names like Janis Joplin.""" self.balance = balance from account import Account
full_name = get_full_name('janis',
'joplin') def deposit(self, amount): @pytest.fixture
assert full_name == 'Janis Joplin' """Add to the balance.""" def account():
self.balance += amount account = Account()
def test_middle(): return account
"""Test names like David Lee Roth.""" def withdraw(self, amount):
full_name = get_full_name('david', """Subtract from the balance.""" def test_initial_balance(account):
'roth', 'lee') self.balance -= amount """Default balance should be 0."""
assert full_name == 'David Lee Roth' assert account.balance == 0
Building a testcase
Running the tests For the first test, we’ll make sure we can start out with different initial
def test_deposit(account):
The two dots after test_full_names.py represent two passing tests. balances. Save this as test_accountant.py.
"""Test a single deposit."""
$ pytest from account import Account account.deposit(100)
============= test session starts ============= assert account.balance == 100
collected 2 items def test_initial_balance():
test_full_names.py .. [100%] """Default balance should be 0.""" def test_withdrawal(account):
account = Account() """Test a deposit followed by withdrawal."""
============== 2 passed in 0.01s ============== assert account.balance == 0 account.deposit(1_000)
account.withdraw(100)
def test_deposit(): assert account.balance == 900
A variety of assert statements """Test a single deposit."""
You can use assert statements in a variety of ways, to account = Account() Running the tests
check for the exact conditions you want to verify. account.deposit(100) $ pytest
Verify that a==b, or a != b assert account.balance == 100 ============= test session starts =============
collected 3 items
assert a == b Running the test
test_account.py ... [100%]
assert a != b $ pytest
Verify that x is True, or x is False ============= test session starts ============= ============== 3 passed in 0.01s ==============
collected 2 items
assert x test_account.py .. [100%]
assert not x pytest flags
============== 2 passed in 0.01s ============== pytest has some flags that can help you run your tests
Verify an item is in a list, or not in a list efficiently, even as the number of tests in your project grows.
assert my_item in my_list When is it okay to modify tests? Stop at the first failing test
assert my_item not in my_list
In general you shouldn’t modify a test once it’s written. When $ pytest -x
a test fails it usually means new code you’ve written has
Running tests from one file broken existing functionality, and you need to modify the new Only run tests that failed during the last test run
In a growing test suite, you can have multiple test files. code until all existing tests pass. $ pytest --last-failed
Sometimes you'll only want to run the tests from one file. If your original requirements have changed, it may be
You can pass the name of a file, and pytest will only run the appropriate to modify some tests. This usually happens in
tests in that file: the early stages of a project when desired behavior is still Weekly posts about all things Python
$ pytest test_names_function.py being sorted out, and no one is using your code yet. mostlypython.substack.com
Beginner's Python
Starting a game (cont.) Pygame rect objects (cont.)
Setting a custom window size Creating a rect object
The display.set_mode() function accepts a tuple that defines the You can create a rect object from scratch. For example a small rect

Cheat Sheet - Pygame screen size.


screen_dim = (1500, 1000)
object that’s filled in can represent a bullet in a game. The Rect()
class takes the coordinates of the upper left corner, and the width
and height of the rect. The draw.rect() function takes a screen
self.screen = pygame.display.set_mode( object, a color, and a rect. This function fills the given rect with the
screen_dim)
What is Pygame? given color.

Pygame is a framework for making games using Setting a custom background color bullet_rect = pygame.Rect(100, 100, 3, 15)
Colors are defined as a tuple of red, green, and blue values. Each color = (100, 100, 100)
Python. Making games is fun, and it’s a great way value ranges from 0-255. The fill() method fills the screen with the
to expand your programming skills and knowledge. color you specify, and should be called before you add any other pygame.draw.rect(screen, color, bullet_rect)
Pygame takes care of many of the lower-level tasks in elements to the screen.
building games, which lets you focus on the aspects of def __init__(self): Working with images
your game that make it interesting. --snip-- Many objects in a game are images that are moved around
self.bg_color = (225, 225, 225) the screen. It’s easiest to use bitmap (.bmp) image files, but
Installing Pygame you can also configure your system to work with jpg, png,
Installing Pygame with pip def run_game(self):
and gif files as well.
while True:
$ python -m pip install --user pygame for event in pygame.event.get(): Loading an image
--snip--
ship = pygame.image.load('images/ship.bmp')
Starting a game
self.screen.fill(self.bg_color) Getting the rect object from an image
The following code sets up an empty game window, and
pygame.display.flip()
starts an event loop and a loop that continually refreshes the ship_rect = ship.get_rect()
screen.
Pygame rect objects Positioning an image
An empty game window With rects, it’s easy to position an image wherever you want on
Many objects in a game can be treated as simple rectangles,
import sys rather than their actual shape. This simplifies code without the screen, or in relation to another object. The following code
import pygame positions a ship at the bottom center of the screen, by matching the
noticeably affecting game play. Pygame has a rect object
midbottom of the ship with the midbottom of the screen.
that makes it easy to work with game objects.
class AlienInvasion: ship_rect.midbottom = screen_rect.midbottom
"""Overall class to manage the game.""" Getting the screen rect object
We already have a screen object; we can easily access the rect Drawing an image to the screen
def __init__(self): object associated with the screen. Once an image is loaded and positioned, you can draw it to the
pygame.init() screen with the blit() method. The blit() method acts on
self.screen_rect = self.screen.get_rect()
self.clock = pygame.time.Clock() the screen object, and takes the image object and image rect as
Finding the center of the screen arguments.
self.screen = pygame.display.set_mode(
(1200, 800)) Rect objects have a center attribute which stores the center point. # Draw ship to screen.
pygame.display.set_caption( screen_center = self.screen_rect.center screen.blit(ship, ship_rect)
"Alien Invasion")
Useful rect attributes Transforming an image
def run_game(self): Once you have a rect object, there are a number of attributes The transform module allows you to make changes to an image
while True: that are useful when positioning objects and detecting relative such as rotation and scaling.
for event in pygame.event.get(): positions of objects. (You can find more attributes in the Pygame rotated_image = pygame.transform.rotate(
if event.type == pygame.QUIT: documentation. The self variable has been left off for clarity.) ship.image, 45)
sys.exit() # Individual x and y values:
screen_rect.left, screen_rect.right
pygame.display.flip() screen_rect.top, screen_rect.bottom
self.clock.tick(60) screen_rect.centerx, screen_rect.centery Python Crash Course
screen_rect.width, screen_rect.height A Hands-on, Project-Based
if __name__ == '__main__':
# Make a game instance, and run the game. Introduction to Programming
# Tuples
ai = AlienInvasion() screen_rect.center ehmatthes.github.io/pcc_3e
ai.run_game() screen_rect.size
Working with images (cont.) Responding to mouse events Pygame groups (cont.)
The blitme() method Pygame’s event loop registers an event any time the mouse Removing an item from a group
Game objects such as ships are often written as classes. Then a moves, or a mouse button is pressed or released. It’s important to delete elements that will never appear again in the
blitme() method is usually defined, which draws the object to the game, so you don’t waste memory and resources.
Responding to the mouse button
screen.
for event in pygame.event.get(): bullets.remove(bullet)
def blitme(self):
if event.type == pygame.MOUSEBUTTONDOWN:
"""Draw ship at current location.""" Detecting collisions
ship.fire_bullet()
self.screen.blit(self.image, self.rect)
You can detect when a single object collides with any
Finding the mouse position
member of a group. You can also detect when any member
Responding to keyboard input The mouse position is returned as a tuple.
of one group collides with a member of another group.
Pygame watches for events such as key presses and mouse mouse_pos = pygame.mouse.get_pos()
actions. You can detect any event you care about in the Collisions between a single object and a group
event loop, and respond with any action that’s appropriate Clicking a button The spritecollideany() function takes an object and a group,
You might want to know if the cursor is over an object such as a and returns True if the object overlaps with any member of the
for your game.
button. The rect.collidepoint() method returns True when a group.
Responding to key presses point overlaps a rect object.
if pygame.sprite.spritecollideany(ship, aliens):
Pygame’s main event loop registers a KEYDOWN event any time a key if button_rect.collidepoint(mouse_pos): ships_left -= 1
is pressed. When this happens, you can check for specific keys.
start_game()
for event in pygame.event.get(): Collisions between two groups
if event.type == pygame.KEYDOWN: Hiding the mouse The sprite.groupcollide() function takes two groups, and two
if event.key == pygame.K_RIGHT: booleans. The function returns a dictionary containing information
pygame.mouse.set_visible(False)
about the members that have collided. The booleans tell Pygame
ship_rect.x += 1
whether to delete the members of either group that have collided.
elif event.key == pygame.K_LEFT:
ship_rect.x -= 1
Pygame groups collisions = pygame.sprite.groupcollide(
elif event.key == pygame.K_SPACE: Pygame has a Group class which makes working with a bullets, aliens, True, True)
ship.fire_bullet() group of similar objects easier. A group is like a list, with
elif event.key == pygame.K_q: some extra functionality that’s helpful when building games. score += len(collisions) * alien_point_value
sys.exit() Making and filling a group
Responding to released keys An object that will be placed in a group must inherit from Sprite. Rendering text
When the user releases a key, a KEYUP event is triggered. from pygame.sprite import Sprite, Group You can use text for a variety of purposes in a game. For
example you can share information with players, and you
for event in pygame.event.get():
class Bullet(Sprite): can display a score.
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT: ... Displaying a message
ship.moving_right = False def draw_bullet(self): The following code defines a message, then a color for the text
... and the background color for the message. A font is defined using
def update(self): the default system font, with a font size of 48. The font.render()
The game is an object ... function is used to create an image of the message, and we get the
In the overall structure shown here (under Starting a Game), rect object associated with the image. We then center the image on
the entire game is written as a class. This makes it possible bullets = Group() the screen and display it.
to write programs that play the game automatically, and
msg = "Play again?"
it also means you can build an arcade with a collection of new_bullet = Bullet()
msg_color = (100, 100, 100)
games. bullets.add(new_bullet)
bg_color = (230, 230, 230)
Looping through the items in a group
Pygame documentation The sprites() method returns all the members of a group. f = pygame.font.SysFont(None, 48)
The Pygame documentation is really helpful when building msg_image = f.render(msg, True, msg_color,
for bullet in bullets.sprites(): bg_color)
your own games. The home page for the Pygame project is
bullet.draw_bullet() msg_image_rect = msg_image.get_rect()
at pygame.org/, and the home page for the documentation is
at pygame.org/docs/. Calling update() on a group msg_image_rect.center = screen_rect.center
The most useful part of the documentation are the screen.blit(msg_image, msg_image_rect)
Calling update() on a group automatically calls update() on each
pages about specific parts of Pygame, such as the Rect() member of the group.
class and the sprite module. You can find a list of these
bullets.update() Weekly posts about all things Python
elements at the top of the help pages. mostlypython.substack.com
Beginner's Python
Customizing plots Customizing plots (cont.)
Plots can be customized in a wide variety of ways. Just Emphasizing points
about any element of a plot can be modified. You can plot as much data as you want on one plot. Here we replot

Cheat Sheet - Using built-in styles


Matplotlib comes with a number of built-in styles, which you can use
with one additional line of code. The style must be specified before
the first and last points larger to emphasize them.
import matplotlib.pyplot as plt

Matplotlib you create the figure.


import matplotlib.pyplot as plt
x_values = list(range(1000))
squares = [x**2 for x in x_values]

x_values = list(range(1000)) fig, ax = plt.subplots()


What is Matplotlib? squares = [x**2 for x in x_values] ax.scatter(x_values, squares, c=squares,
cmap=plt.cm.Blues, s=10)
Data visualization involves exploring data through
visual representations. The Matplotlib library helps you plt.style.use('seaborn-v0_8')
fig, ax = plt.subplots() ax.scatter(x_values[0], squares[0], c='green',
make visually appealing representations of the data ax.scatter(x_values, squares, s=10) s=100)
you’re working with. Matplotlib is extremely flexible; ax.scatter(x_values[-1], squares[-1], c='red',
these examples will help you get started with a few plt.show() s=100)
simple visualizations.
Seeing available styles ax.set_title('Square Numbers', fontsize=24)
Many newer plotting libraries are wrappers around --snip--
You can see all available styles on your system. This can be done in
Matplotlib, and understanding Matplotlib will help you a terminal session.
use those libraries more effectively as well. Removing axes
>>> import matplotlib.pyplot as plt You can customize or remove axes entirely. Here’s how to access
>>> plt.style.available
Installing Matplotlib ['Solarize_Light2', '_classic_test_patch', ...
each axis, and hide it.

Installing Matplotlib with pip ax.get_xaxis().set_visible(False)


Adding titles and labels, and scaling axes ax.get_yaxis().set_visible(False)
$ python -m pip install --user matplotlib
import matplotlib.pyplot as plt Setting a custom figure size
Line graphs and scatter plots x_values = list(range(1000))
You can make your plot as big or small as you want by using the
figsize argument. The dpi argument is optional; if you don’t know
Making a line graph squares = [x**2 for x in x_values] your system’s resolution you can omit the argument and adjust the
The fig object represents the entire figure, or collection of plots; ax figsize argument accordingly.
represents a single plot in the figure. This convention is used even # Set overall style to use, and plot data.
fig, ax = plt.subplots(figsize=(10, 6),
when there's only one plot in the figure. plt.style.use('seaborn-v0_8')
dpi=128)
fig, ax = plt.subplots()
import matplotlib.pyplot as plt
ax.scatter(x_values, squares, s=10) Saving a plot
x_values = [0, 1, 2, 3, 4, 5] The Matplotlib viewer has a save button, but you can also save
# Set chart title and label axes. your visualizations programmatically by replacing plt.show() with
squares = [0, 1, 4, 9, 16, 25]
ax.set_title('Square Numbers', fontsize=24) plt.savefig(). The bbox_inches argument reduces the amount of
ax.set_xlabel('Value', fontsize=14) whitespace around the figure.
fig, ax = plt.subplots()
ax.set_ylabel('Square of Value', fontsize=14)
ax.plot(x_values, squares) plt.savefig('squares.png', bbox_inches='tight')
# Set scale of axes, and size of tick labels.
plt.show() Online resources
ax.axis([0, 1100, 0, 1_100_000])
Making a scatter plot ax.tick_params(axis='both', labelsize=14) The matplotlib gallery and documentation are at
scatter() takes a list of x and y values; the s=10 argument matplotlib.org/. Be sure to visit the Examples, Tutorials, and
controls the size of each point. plt.show() User guide sections.
import matplotlib.pyplot as plt Using a colormap

x_values = list(range(1000))
A colormap varies the point colors from one shade to another, based
on a certain value for each point. The value used to determine Python Crash Course
squares = [x**2 for x in x_values] the color of each point is passed to the c argument, and the cmap A Hands-on, Project-Based
argument specifies which colormap to use. Introduction to Programming
fig, ax = plt.subplots() ax.scatter(x_values, squares, c=squares,
ax.scatter(x_values, squares, s=10) ehmatthes.github.io/pcc_3e
cmap=plt.cm.Blues, s=10)
plt.show()
Multiple plots Working with dates and times (cont.) Multiple plots in one figure
You can make as many plots as you want on one figure. Datetime formatting arguments You can include as many individual graphs in one figure as
When you make multiple plots, you can emphasize The strptime() function generates a datetime object from a you want.
relationships in the data. For example you can fill the space string, and the strftime() method generates a formatted string
Sharing an x-axis
between two sets of data. from a datetime object. The following codes let you work with dates
The following code plots a set of squares and a set of cubes on
exactly as you need to.
Plotting two sets of data two separate graphs that share a common x-axis. The plt.
Here we use ax.scatter() twice to plot square numbers and %A Weekday name, such as Monday subplots() function returns a figure object and a tuple of axes.
cubes on the same figure. %B Month name, such as January Each set of axes corresponds to a separate plot in the figure.
%m Month, as a number (01 to 12) The first two arguments control the number of rows and columns
import matplotlib.pyplot as plt %d Day of the month, as a number (01 to 31) generated in the figure.
%Y Four-digit year, such as 2021 import matplotlib.pyplot as plt
x_values = list(range(11)) %y Two-digit year, such as 21
squares = [x**2 for x in x_values] %H Hour, in 24-hour format (00 to 23)
cubes = [x**3 for x in x_values] x_values = list(range(11))
%I Hour, in 12-hour format (01 to 12) squares = [x**2 for x in x_values]
%p AM or PM cubes = [x**3 for x in x_values]
plt.style.use('seaborn-v0_8') %M Minutes (00 to 59)
fig, ax = plt.subplots() %S Seconds (00 to 61) fig, axs = plt.subplots(2, 1, sharex=True)
ax.scatter(x_values, squares, c='blue', s=10) Converting a string to a datetime object
ax.scatter(x_values, cubes, c='red', s=10) axs[0].scatter(x_values, squares)
new_years = dt.strptime('1/1/2023', '%m/%d/%Y') axs[0].set_title('Squares')
plt.show() Converting a datetime object to a string axs[1].scatter(x_values, cubes, c='red')
Filling the space between data sets ny_string = new_years.strftime('%B %d, %Y') axs[1].set_title('Cubes')
The fill_between() method fills the space between two data sets. print(ny_string)
It takes a series of x-values and two series of y-values. It also takes plt.show()
a facecolor to use for the fill, and an optional alpha argument that Plotting high temperatures
controls the color’s transparency. The following code creates a list of dates and a corresponding list of Sharing a y-axis
high temperatures. It then plots the high temperatures, with the date To share a y-axis, use the sharey=True argument.
ax.fill_between(x_values, cubes, squares, labels displayed in a specific format.
facecolor='blue', alpha=0.25) import matplotlib.pyplot as plt
from datetime import datetime as dt
x_values = list(range(11))
Working with dates and times import matplotlib.pyplot as plt squares = [x**2 for x in x_values]
Many interesting data sets have a date or time as the x from matplotlib import dates as mdates cubes = [x**3 for x in x_values]
value. Python’s datetime module helps you work with this
kind of data. dates = [ plt.style.use('seaborn-v0_8')
dt(2023, 6, 21), dt(2023, 6, 22), fig, axs = plt.subplots(1, 2, sharey=True)
Generating the current date dt(2023, 6, 23), dt(2023, 6, 24),
The datetime.now() function returns a datetime object ] axs[0].scatter(x_values, squares)
representing the current date and time.
axs[0].set_title('Squares')
from datetime import datetime as dt highs = [56, 57, 57, 64]
axs[1].scatter(x_values, cubes, c='red')
today = dt.now() plt.style.use('seaborn-v0_8') axs[1].set_title('Cubes')
date_string = today.strftime('%m/%d/%Y') fig, ax = plt.subplots()
print(date_string) ax.plot(dates, highs, c='red') plt.show()
Generating a specific date ax.set_title("Daily High Temps", fontsize=24)
You can also generate a datetime object for any date and time you ax.set_ylabel("Temp (F)", fontsize=16)
want. The positional order of arguments is year, month, and day. x_axis = ax.get_xaxis()
The hour, minute, second, and microsecond arguments are optional. x_axis.set_major_formatter(
from datetime import datetime as dt mdates.DateFormatter('%B %d %Y')
)
new_years = dt(2023, 1, 1) fig.autofmt_xdate()
fall_equinox = dt(year=2023, month=9, day=22) Weekly posts about all things Python
plt.show()
mostlypython.substack.com
Beginner's Python
Line graphs, scatter plots, and bar graphs Further customizations
(cont.) You can make a wide variety of further customizations to
a plot using the update methods. For example, update_
Making a bar graph
Cheat Sheet - Plotly fig = px.bar(x=x_values, y=squares)
layout() gives you control of many formatting options.
Using update_layout()
Here the update_layout() method is used to change the font
Initial customizations sizes, and change the tick mark spacing on the x-axis.
What is Plotly? The functions that generate plots also accept parameters import plotly.express as px
Data visualization involves exploring data through that specify titles, labels, and other formatting directives for
visual representations. Plotly helps you make visually your visualizations. x_values = list(range(11))
appealing representations of the data you’re working Adding a title and axis labels squares = [x**2 for x in x_values]
with. Plotly is particularly well suited for visualizations The title is a string. The labels dictionary lets you specify which
that will be presented online, because it supports aspects of the plot will have custom labels. title = "Square Numbers"
labels = {'x': 'Value', 'y': 'Square of Value'}
interactive elements. import plotly.express as px
Plotly express lets you see a basic version of your fig = px.scatter(
plot with just a few lines of code. Once you know the # Define the data. x=x_values,
plot works for your data, you can refine the style of x_values = list(range(11)) y=squares,
squares = [x**2 for x in x_values] ...
your plot.
)
# Visualize the data.
Installing Plotly title = "Square Numbers" fig.update_layout(
Plotly Express requires the pandas library. labels = {'x': 'Value', 'y': 'Square of Value'} title_font_size=30,
Installing Plotly with pip xaxis_title_font_size=24,
fig = px.scatter(x=x_values, y=squares, xaxis_dtick=1,
$ python -m pip install --user plotly title=title, labels=labels) xaxis_tickfont_size=16,
$ python -m pip install --user pandas fig.show() yaxis_title_font_size=24,
More customizations in the plotting call yaxis_tickfont_size=16,
Line graphs, scatter plots, and bar graphs Plotly Express was designed to give you as much control as
)
To make a plot with Plotly Express, you specify the data and possible, using as little code as possible. Here's a small example of
then create a fig object. The call to fig.show() opens the how much can be customized within a single plotting call. fig.show()
plot in a new browser tab. You have a plot in just two lines of Most of these arguments can be single values, or sequences that
code! match the size of the overall dataset. Plotly Express documentation
Making a line graph import plotly.express as px Plotly's documentation is extensive and well-organized.
Plotly generates JavaScript code to render the plot file. If you're There's a lot of it, though, so it can be hard to know where to
curious to see the code, open your browser's inspector tool when x_values = list(range(11)) begin. Start with an overview of Plotly Express at plotly.com/
the plot opens. squares = [x**2 for x in x_values] python/plotly-express. This page itself is helpful; make sure
you also click on the documentation for the kinds of plots
import plotly.express as px title = "Square Numbers" you use most often. These lead to pages full of discussions
labels = {'x': 'Value', 'y': 'Square of Value'} and examples.
# Define the data.
x_values = list(range(11)) Also see the Python API reference for plotly at plotly.
fig = px.scatter( com/python-api-reference. This is a reference page showing
squares = [x**2 for x in x_values] x=x_values,
all the different kinds of plots you can make with Plotly. If you
y=squares,
# Visualize the data. click on any of the links, you can see all the arguments that
title=title,
fig = px.line(x=x_values, y=squares) can be included in plotting calls.
labels=labels,
fig.show() size=squares,

Python Crash Course


Making a scatter plot color=squares,
opacity=0.5,
To make a scatter plot, change line() to scatter(). This is the
point of Plotly Express; you can easily see your data in a variety of
width=1200, A Hands-on, Project-Based
ways before committing to a more specific styling options. height=800, Introduction to Programming
)
fig = px.scatter(x=x_values, y=squares) ehmatthes.github.io/pcc_3e
fig.show()
Using a predefined theme Using Subplots Plotting global datasets
A theme is a set of styles applied to a visualization in Plotly. It's often useful to have multiple plots share the same axes. Plotly has a variety of mapping tools. For example, if you
Themes are implemented with templates. This is done using the subplots module. have a set of points represented by latitude and longitude,
you can create a scatter plot of those points overlaying a
Using a theme Adding subplots to a figure
map.
To use the subplots module, make a figure to hold all the charts
import plotly.express as px
that will be made. Then use the add_trace() method to add each The scattergeo chart type
data series to the overall figure. Here's a map showing the location of three of the higher peaks in
# Define the data. All individual plots need to be made using the graph_objects
x_values = list(range(11)) North America. If you hover over each point, you'll see its location
module. and the name of the mountain.
squares = [x**2 for x in x_values]
from plotly.subplots import make_subplots import plotly.express as px
# Visualize the data. import plotly.graph_objects as go
title = "Square Numbers" # Points in (lat, lon) format.
labels = {'x': 'Value', 'y': 'Square of Value'} x_values = list(range(11)) peak_coords = [
squares = [x**2 for x in x_values] (63.069, -151.0063),
fig = px.scatter(x=x_values, y=squares, cubes = [x**3 for x in x_values] (60.5671, -140.4055),
title=title, labels=labels, (46.8529, -121.7604),
template='plotly_dark') # Make two subplots, sharing a y-axis. ]
fig.show() fig = make_subplots(rows=1, cols=2,
shared_yaxes=True) # Make matching lists of lats, lons,
Viewing all available themes # and labels.
>>> import plotly.io as pio # Start by plotting the square numbers. lats = [pc[0] for pc in peak_coords]
>>> pio.templates squares_trace = go.Scatter(x=x_values, lons = [pc[1] for pc in peak_coords]
Templates configuration y=squares)
----------------------- fig.add_trace(squares_trace, row=1, col=1) peak_names = [
Default template: 'plotly' "Denali",
Available templates: # Add a new trace for the cubes. "Mt Logan",
['ggplot2', 'seaborn',..., cubes_trace = go.Scatter(x=x_values, y=cubes) "Mt Rainier"
'ygridoff', 'gridon', 'none'] fig.add_trace(cubes_trace, row=1, col=2) ]
elevations = [20_000, 18_000, 14_000]
title = "Squares and Cubes"
Adding traces to a Plotly Express plot fig.update_layout(title_text=title) # Generate initial map.
In Plotly, a trace is a dataset that can be plotted on a title = "Selected High Peaks"
chart. You can add traces to existing Plotly Express plots. fig.show() fig = px.scatter_geo(
Additional plots need to be specified using the graph_objects lat=lats,
module. Further documentation lon=lons,
title=title,
Using fig.add_trace() After exploring the Plotly Express documenation, look at
projection="natural earth",
Styling Plotly Express Figures in Python, at plotly.com/
import plotly.express as px text=peak_names,
python/styling-plotly-express. This explains all the ways
import plotly.graph_objects as go size=elevations,
you can style and format plots. After that, the Python Figure scope="north america",
days = list(range(1, 10)) Reference (plotly.com/python/reference/index) will be much )
highs = [60, 63, 68, 70, 68, 70, 66, 62, 64] more useful. It shows you all the possible settings you can
lows = [51, 54, 53, 57, 54, 56, 52, 53, 49] change, with examples for each. # Customize formatting options.
Make sure you read about "magic underscores" in Plotly, fig.update_layout(titlefont_size=24)
# Start by plotting low temperaturs. at plotly.com/python/creating-and-updating-figures. They fig.update_traces(
fig = px.line(x=days, y=lows) take a little getting used to, but once you're familiar with textposition="middle right",
the syntax they make it much easier to specify exactly the textfont_size=18,
# Add a new trace for the high temperatures. settings you want to modify. )
new_trace = go.Scatter(x=days, y=highs,
mode='lines') If you're using subplots, read Subplots in Python at plotly. fig.show()
fig.add_trace(new_trace) com/python/subplots. Also look at Graph Objects in Python
at plotly.com/python/graph-objects, which are used to make
fig.show() individual plots in a subplot. Weekly posts about all things Python
mostlypython.substack.com
Beginner's Python
Working with models Building a simple home page
The data in a Django project is structured as a set of models. Users interact with a project through web pages, and a
Each model is represented by a class. project’s home page can start out as a simple page with no

Cheat Sheet - Django Defining a model


To define the models for your app, modify the models.py file that
was created in your app’s folder. The __str__() method tells
data. A page usually needs a URL, a view, and a template.
Mapping a project's URLs
The project’s main urls.py file tells Django where to find the urls.py
Django how to represent data objects based on this model. files associated with each app in the project.
What is Django? from django.db import models from django.contrib import admin
Django is a web framework that helps you build from django.urls import path, include
interactive websites using Python. With Django you class Topic(models.Model):
define the kind of data your site will work with, and the """A topic the user is learning about.""" urlpatterns = [
ways your users can work with that data. path('admin/', admin.site.urls),
text = models.CharField(max_length=200) path('', include('learning_logs.urls')),
Django works well for tiny projects, and just as well date_added = models.DateTimeField( ]
for sites with millions of users. auto_now_add=True)
Mapping an app's URLs
Installing Django def __str__(self): An app’s urls.py file tells Django which view to use for each URL
It’s best to install Django to a virtual environment, where return self.text in the app. You’ll need to make this file yourself, and save it in the
app’s folder.
your project can be isolated from your other Python projects.
Activating a model
Most commands assume you’re working in an active virtual from django.urls import path
To use a model the app must be added to the list INSTALLED_APPS,
environment.
which is stored in the project’s settings.py file.
from . import views
Create a virtual environment INSTALLED_APPS = [
$ python –m venv ll_env # My apps. app_name = 'learning_logs'
'learning_logs', urlpatterns = [
Activate the environment (macOS and Linux) # Home page.
$ source ll_env/bin/activate # Default Django apps. path('', views.index, name='index'),
'django.contrib.admin', ]
Activate the environment (Windows) ]
Writing a simple view
> ll_env\Scripts\activate Migrating the database A view takes information from a request and sends data to the
Install Django to the active environment The database needs to be modified to store the kind of data that the browser, often through a template. View functions are stored in an
model represents. You'll need to run these commands every time app’s views.py file. This simple view function doesn’t pull in any
(ll_env)$ pip install Django you create a new model, or modify an existing model. data, but it uses the template index.html to render the home page.
$ python manage.py makemigrations learning_logs from django.shortcuts import render
Creating a project $ python manage.py migrate
To start we’ll create a new project, create a database, and def index(request):
Creating a superuser """The home page for Learning Log."""
start a development server.
A superuser is a user account that has access to all aspects of the return render(request,
Create a new project project. 'learning_logs/index.html')
Make sure to include the dot at the end of this command. $ python manage.py createsuperuser
$ django-admin startproject ll_project .
Registering a model
Online resources
Create a database You can register your models with Django’s admin site, which makes The documentation for Django is available at
it easier to work with the data in your project. To do this, modify the docs.djangoproject.com/. The Django documentation is
$ python manage.py migrate app’s admin.py file. View the admin site at http://localhost:8000/ thorough and user-friendly, so check it out!
View the project admin/. You'll need to log in using a superuser account.
After issuing this command, you can view the project at http:// from django.contrib import admin
localhost:8000/.
from .models import Topic
Python Crash Course
$ python manage.py runserver A Hands-on, Project-Based
Create a new app admin.site.register(Topic) Introduction to Programming
A Django project is made up of one or more apps. ehmatthes.github.io/pcc_3e
$ python manage.py startapp learning_logs
Building a simple home page (cont.) Another model Building a page with data (cont.)
Writing a simple template A new model can use an existing model. The ForeignKey Using data in a template
A template sets up the structure for a page. It’s a mix of html and attribute establishes a connection between instances of the The data in the view function’s context dictionary is available within
template code, which is like Python but not as powerful. Most of the two related models. Make sure to migrate the database after the template. This data is accessed using template variables, which
logic for your project should be written in .py files, but some logic is adding a new model to your app. are indicated by doubled curly braces.
appropriate for templates. The vertical line after a template variable indicates a filter. In
Make a folder called templates/ inside the project folder. Inside Defining a model with a foreign key this case a filter called date formats date objects, and the filter
the templates/ folder make another folder with the same name as class Entry(models.Model): linebreaks renders paragraphs properly on a web page.
the app. This is where the template files should be saved. The home """Learning log entries for a topic."""
page template will be saved as learning_logs/templates/learning_ {% extends 'learning_logs/base.html' %}
topic = models.ForeignKey(Topic,
logs/index.html.
on_delete=models.CASCADE) {% block content %}
<p>Learning Log</p> text = models.TextField()
date_added = models.DateTimeField( <p>Topic: {{ topic }}</p>
<p>Learning Log helps you keep track of your auto_now_add=True)
learning, for any topic you're learning <p>Entries:</p>
about.</p> def __str__(self): <ul>
return f"{self.text[:50]}..." {% for entry in entries %}
Template Inheritance <li>
Many elements of a web page are repeated on every page Building a page with data <p>
Most pages in a project need to present data that’s specific {{ entry.date_added|date:'M d, Y H:i' }}
in the site, or every page in a section of the site. By writing
</p>
one parent template for the site, and one for each section, to the current user.
you can easily modify the look and feel of your entire site. URL parameters <p>
The parent template A URL often needs to accept a parameter telling it what data to {{ entry.text|linebreaks }}
The parent template defines the elements common to a set of access from the database. The URL pattern shown here looks for </p>
pages, and defines blocks that will be filled by individual pages. the ID of a specific topic and assigns it to the parameter topic_id. </li>
urlpatterns = [ {% empty %}
<p> <li>There are no entries yet.</li>
<a href="{% url 'learning_logs:index' %}"> --snip--
# Detail page for a single topic. {% endfor %}
Learning Log </ul>
</a> path('topics/<int:topic_id>/', views.topic,
</p> name='topic'),
] {% endblock content %}
{% block content %}{% endblock content %}
Using data in a view The Django shell
The child template The view uses a parameter from the URL to pull the correct data
You can explore the data in your project from the command
The child template uses the {% extends %} template tag to pull in from the database. In this example the view is sending a context
dictionary to the template, containing data that should be displayed line. This is helpful for developing queries and testing code
the structure of the parent template. It then defines the content for
on the page. You'll need to import any model you're using. snippets.
any blocks defined in the parent template.
{% extends 'learning_logs/base.html' %} def topic(request, topic_id): Start a shell session
"""Show a topic and all its entries.""" $ python manage.py shell
{% block content %} topic = Topic.objects.get(id=topic_id)
entries = topic.entry_set.order_by( Access data from the project
<p> '-date_added')
>>> from learning_logs.models import Topic
Learning Log helps you keep track context = {
>>> Topic.objects.all()
of your learning, for any topic you're 'topic': topic,
[<Topic: Chess>, <Topic: Rock Climbing>]
learning about. 'entries': entries,
>>> topic = Topic.objects.get(id=1)
</p> }
>>> topic.text
return render(request,
'Chess'
{% endblock content %} 'learning_logs/topic.html', context)
>>> topic.entry_set.all()
<QuerySet [<Entry: In the opening phase...>]>
Template indentation Restarting the development server
Python code is usually indented by four spaces. In templates If you make a change to your project and the change doesn’t
you’ll often see two spaces used for indentation, because seem to have any effect, try restarting the server: Weekly posts about all things Python
elements tend to be nested more deeply in templates. $ python manage.py runserver mostlypython.substack.com
Beginner's Python
User accounts (cont.) User accounts (cont.)
Defining the URLs Showing the current login status
Users will need to be able to log in, log out, and register. Make a You can modify the base.html template to show whether the user

Cheat Sheet - new urls.py file in the users app folder.


from django.urls import path, include
is currently logged in, and to provide a link to the login and logout
pages. Django makes a user object available to every template,
and this template takes advantage of this object.

Django, Part 2
Testing for user.is_authenticated in a template allows you
from . import views to serve specific content to users depending on whether they have
logged in or not. The {{ user.username }} property allows you to
app_name = 'accounts' greet users who have logged in. Users who haven’t logged in see
urlpatterns = [ links to register or log in.
Users and forms # Include default auth urls.
<p>
path('', include(
Most web applications need to let users make <a href="{% url 'learning_logs:index' %}">
'django.contrib.auth.urls')),
accounts, so they can create and work with their own Learning Log
data. Some of this data may be private, and some may </a>
# Registration page.
be public. Django’s forms allow users to enter and path('register/', views.register,
{% if user.is_authenticated %}
modify their data. name='register'),
Hello, {{ user.username }}.
]
<a href="{% url 'accounts:logout' %}">
User accounts The login template Log out
User accounts are handled by a dedicated app which we'll The login view is provided by default, but you need to provide your </a>
call accounts. Users need to be able to register, log in, and own login template. The template shown here displays a simple {% else %}
log out. Django automates much of this work for you. login form, and provides basic error messages. Make a templates/ <a href="{% url 'accounts:register' %}">
folder in the accounts/ folder, and then make a registration/ folder in Register
Making an accounts app the templates/ folder. Save this file as login.html. The path should be </a> -
After making the app, be sure to add 'accounts' to INSTALLED_ accounts/templates/registration/login.html. <a href="{% url 'accounts:login' %}">
APPS in the project’s settings.py file. The tag {% csrf_token %} helps prevent a common type of Log in
$ python manage.py startapp accounts attack with forms. The {{ form.as_div }} element displays the </a>
default login form in an appropriate format. {% endif %}
Including URLs for the accounts app {% extends "learning_logs/base.html" %}
Add a line to the project’s urls.py file so the accounts app’s URLs </p>
are included in the project. {% block content %}
from django.contrib import admin {% block content %}{% endblock content %}
from django.urls import path, include {% if form.errors %}
<p>
The logout form
Django handles logout functionality, but you need to give users
urlpatterns = [ Your username and password didn't match.
a simple form to submit that logs them out. Make sure to add the
path('admin/', admin.site.urls), Please try again.
LOGOUT_REDIRECT_URL to settings.py.
path('accounts/', include('accounts.urls')), </p>
path('', include('learning_logs.urls')), {% endif %} {% if user.is_authenticated %}
] <form action="{% url 'accounts:logout' %}"
<form action="{% url 'users:login' method='post'>
method="post" %}">
Using forms in Django {% csrf_token %}
There are a number of ways to create forms and work {% csrf token %} <button name='submit'>Log out</button>
with them. You can use Django’s defaults, or completely {{ form.as_div }}
customize your forms. For a simple way to let users enter <button name="submit">Log in</button> </form>
data based on your models, use a ModelForm. This creates {% endif %}
a form that allows users to enter data that will populate the </form>
fields on a model.
The register view on the back of this sheet shows a
simple approach to form processing. If the view doesn’t
{% endblock content %} Python Crash Course
receive data from a form, it responds with a blank form. If The logout redirect setting in settings.py A Hands-on, Project-Based
it receives POST data from a form, it validates the data and This setting tells Django where to send users after they log out. Introduction to Programming
then saves it to the database. LOGOUT_REDIRECT_URL = 'learning_logs:index' ehmatthes.github.io/pcc_3e
User accounts (cont.) User accounts (cont.) Connecting data to users (cont.)
The register view The register template Restricting access to logged-in users
The register view needs to display a blank registration form when The register.html template shown here displays the registration form Some pages are only relevant to registered users. The views for
the page is first requested, and then process completed registration in a simple format. these pages can be protected by the @login_required decorator.
forms. Any view with this decorator will automatically redirect non-logged in
A successful registration logs the user in and redirects to the
{% extends 'learning_logs/base.html' %} users to an appropriate page. Here’s an example views.py file.
home page. An invalid form displays the registration page again,
with an appropriate error message. {% block content %} from django.contrib.auth.decorators import \
login_required
from django.shortcuts import render, redirect <form action="{% url 'accounts:register' --snip--
from django.contrib.auth import login method='post' %}">
from django.contrib.auth.forms import \ @login_required
UserCreationForm {% csrf_token %} def topic(request, topic_id):
{{ form.as_div }} """Show a topic and all its entries."""
def register(request):
"""Register a new user.""" <button name='submit'>Register</button>
Setting the redirect URL
The @login_required decorator sends unauthorized users to the
if request.method != 'POST': login page. Add the following line to your project’s settings.py file so
</form>
# Display blank registration form. Django will know how to find your login page.
form = UserCreationForm() {% endblock content %} LOGIN_URL = 'accounts:login'

else: Preventing inadvertent access


# Process completed form. Connecting data to users Some pages serve data based on a parameter in the URL. You can
form = UserCreationForm( Users will create some data that belongs to them. Any model check that the current user owns the requested data, and return a
data=request.POST) that should be connected directly to a user needs a field 404 error if they don’t. Here’s an example view.
connecting instances of the model to a specific user. from django.http import Http404
if form.is_valid(): --snip--
new_user = form.save()
Making a topic belong to a user
Only the highest-level data in a hierarchy needs to be directly
connected to a user. To do this import the User model, and add it as @login_required
# Log in, redirect to home page. def topic(request, topic_id):
a foreign key on the data model.
login(request, new_user) After modifying the model you’ll need to migrate the database. """Show a topic and all its entries."""
return redirect( You’ll need to choose a user ID to connect each existing instance to. topic = Topics.objects.get(id=topic_id)
'learning_logs:index') if topic.owner != request.user:
from django.db import models
raise Http404
# Display a blank or invalid form. from django.contrib.auth.models import User
--snip--
context = {'form': form}
class Topic(models.Model):
return render(request, """A topic the user is learning about.""" Using a form to edit data
'registration/register.html', context) If you provide some initial data, Django generates a form
text = models.CharField(max_length=200) with the user’s existing data. Users can then modify and
date_added = models.DateTimeField( save their data.
Styling your project auto_now_add=True)
The django-bootstrap5 app allows you to use the Creating a form with initial data
Bootstrap library to make your project look visually owner = models.ForeignKey(User, The instance parameter allows you to specify initial data for a form.
appealing. The app provides tags that you can use in your on_delete=models.CASCADE) form = EntryForm(instance=entry)
templates to style individual elements on a page. Learn
more at django-bootstrap5.readthedocs.io/. def __str__(self): Modifying data before saving
return self.text The argument commit=False allows you to make changes before
Deploying your project Querying data for the current user
writing data to the database.

Platform.sh lets you push your project to a live server, In a view, the request object has a user attribute. You can use this new_topic = form.save(commit=False)
making it available to anyone with an internet connection. attribute to query for the user’s data. The filter() method shown new_topic.owner = request.user
Platform.sh offers a free service level, which lets you learn here pulls the data that belongs to the current user. new_topic.save()
the deployment process without any commitment. topics = Topic.objects.filter(
You’ll need to install a set of Platform.sh command line owner=request.user) Weekly posts about all things Python
tools, and use Git to track the state of your project. See
https://platform.sh/marketplace/django for more information. mostlypython.substack.com
Beginner's Python
Ignoring files (cont.) Checking the log
Ignore specific files Git logs all the commits you've made. Checking the log is
helpful for understanding the history of your project.

Cheat Sheet - Git


.DS_Store
secret_key.txt Check log in default format
Ignore files with specific extensions $ git log
commit dc2ebd6... (HEAD -> main)
*.pyc Author: Eric Matthes <eric@example.com>
Version Control
Date: Feb 27 11:27:07 2023 -0900
Version control software allows you to take snapshots Initializing a repository Greets user.
of a project whenever it’s in a working state. If your All the files Git uses to manage the repository are located in commit bf55851...
project stops working, you can roll back to the most ...
the hidden directory .git. Don't delete that directory, or you'll
recent working version of the project. lose your project's history. Check log in simpler format
Version control is important because it frees you
Initialize a repository $ git log --oneline
to try new ideas with your code, without worrying that
$ git init dc2ebd6 (HEAD -> main) Greets uer.
you’ll break your overall project. A distributed version bf55851 Started project, everything works.
Initialized empty Git repository in
control system like Git is also really useful in working
my_project/.git/
collaboratively with other developers. Exploring history
Installing Git Checking the status You can explore a project's history by visiting specific
It's important to check the status of your project often, even commit hashes, or by referencing the project's HEAD. HEAD
You can find an installer for your system at git-scm.com/. refers to the most recent commit of the current branch.
Before doing that, check if Git is already on your system: before the first commit. This will tell you which files Git is
planning to track. Visit a specific commit
$ git --version
git version 2.30.1 (Apple Git-130) Check status $ git checkout b9aedbb
$ git status Return to most recent commit of main branch
Configuring Git On branch main
$ git checkout main
No commits yet
You can configure Git so some of its features are easier to
Untracked files:
use. The editor setting controls which editor Git will open Visit the previous commit
.gitignore
when it needs you to enter text. hello.py $ git checkout HEAD^
See all global settings ...
Visit an earlier commit
$ git config --list
Adding files $ git checkout HEAD^^^
Set username You'll need to add the files you want Git to keep track of. Visit the previous commit
$ git config --global user.name "eric" Add all files not in .gitignore $ git checkout HEAD~1
Set email $ git add . Vist an earlier commit
$ git config --global user.email Add a single file $ git checkout HEAD~3
"eric@example.com"
$ git add hello.py
Set editor Learning more
$ git config --global core.editor "nano" Making a commit You can learn more about using Git with the command git
When making a commit, the -am flag commits all files that help. You can also go to Stack Overflow and search for git,
Ignoring files have been added, and records a commit message. (It's a and then sort the questions by number of votes.
To ignore files make a file called ".gitignore", with a leading good idea to check the status before making each commit.)
dot and no extension. Then list the directories and files you
want to ignore.
Make a commit with a message Python Crash Course
$ git commit -am "Started project, everything A Hands-on, Project-Based
Ignore directories works." Introduction to Programming
__pycache__/ 2 files changed, 7 insertions(+)
create mode 100644 .gitignore ehmatthes.github.io/pcc_3e
my_venv/
create mode 100644 hello.py
Branching Stashing changes Git & GitHub
When the work you're about to do will involve multiple If you want to save some changes without making a commit, GitHub is a platform for sharing code, and working
commits, you can create a branch where you'll do this work. you can stash your changes. This is useful when you want to collaboratively on code. You can clone any public project on
The changes you make will be kept away from your main revisit the most recent commit without making a new commit. GitHub. When you have an account, you can upload your
branch until you choose to merge them. It's common to You can stash as many sets of changes as you need. own projects, and make them public or private.
delete a branch after merging back to the main branch.
Stash changes since last commit Clone an existing repository to your local system
Branches can also be used to maintain independent
releases of a project. $ git stash $ git clone
Saved working directory and index state https://github.com/ehmatthes/pcc_3e.git/
Make a new branch and switch to it WIP on main: f6f39a6... Cloning into 'pcc_3e'...
$ git checkout -b new_branch_name ...
Switched to a new branch 'new_branch_name'
See stashed changes Resolving deltas: 100% (1503/1503), done.
$ git stash list
See all branches stash@{0}: WIP on main: f6f39a6...
Push a local project to a GitHub repository
You'll need to make an empty repository on GitHub first.
$ git branch stash@{1}: WIP on main: f6f39a6...
main ... $ git remote add origin
* new_branch_name https://github.com/username/hello_repo.git
Reapply changes from most recent stash $ git push -u origin main
Switch to a different branch $ git stash pop Enumerating objects: 10, done.
$ git checkout main ...
Switched to branch 'main'
Reapply changes from a specific stash To https://github.com/username/hello_repo.git
$ git stash pop --index 1 * [new branch] main -> main
Merge changes Branch 'main' set up to track remote branch
$ git merge new_branch_name
Clear all stashed changes 'main' from 'origin'.
Updating b9aedbb..5e5130a $ git stash clear Push recent changes to your GitHub repository
Fast-forward
hello.py | 5 +++++ $ git push origin branch_name
Comparing commits
1 file changed, 5 insertions(+)
It's often helpful to compare changes across different states
Delete a branch of a project.
Using pull requests
When you want to pull a set of changes from one branch
$ git branch -D new_branch_name See all changes since last commit into the main branch of a project on GitHub, you can make
Deleted branch new_branch_name a pull request. To practice making pull requests on your own
$ git diff
(was 5e5130a). repositories, make a new branch for your work. When you're
Move last commit to new branch See changes in one file since last commit finished the work, push the branch to your repository. Then
$ git diff hello.py go to the "Pull requests" tab on GitHub, and click "Compare
$ git branch new_branch_name & pull request" on the branch you wish to merge. When
$ git reset --hard HEAD~1 See changes since a specific commit you're ready, click "Merge pull request".
$ git checkout new_branch_name
$ git diff HEAD~2 You can then pull these changes back into your local main
$ git diff HEAD^^ branch with git pull origin main. This is an alternative
Undoing recent changes $ git diff fab2cdd to merging changes to your main branch locally, and then
One of the main points of version control is to allow you to pushing the main branch to GitHub.
go back to any working state of your project and start over See changes between two commits
from there. $ git diff fab2cdd 7c0a5d8 Practicing with Git
Get rid of all uncommited changes See changes in one file between two commits Git can be used in simple ways as a solo developer, and
complex ways as part of a large collaborative team. You can
$ git checkout . $ git diff fab2cdd 7c0a5d8 hello.py gain valuable experience by making a simple throwaway
Get rid of all changes since a specific commit project and trying all of these steps with that project. Make
$ git reset --hard b9aedbb
Good commit habits sure your project has multiple files and nested folders to get
Try to make a commit whenever your project is in a new a clear sense of how Git works.
Create new branch starting at a previous commit working state. Make sure you're writing concise commit
$ git checkout -b branch_name b9aedbb messages that focus on what changes have been
Weekly posts about all things Python
implemented. If you're starting work on a new feature or
bugfix, consider making a new branch. mostlypython.substack.com

You might also like