Supplemental Resources
In addition to the core class resources which we expect every student to engage with, we have many additional resources to help you understand programming, which may be more or less useful for specific students. Reading, watching, or listening to these materials is optional, but we expect that if you are having trouble understanding things, you will make use of these resources to help review the class concepts from a different angle, and for many students, using some of these resources every week may be helpful. Use the links in the table of contents below to jump to specific resources.
Table of Contents
- Extra Programs (extra programs for the class)
- Reference Pages (our course reference pages for specific details on programming concepts and functions)
- Short Explanations (one-time explanations that
should take a short time to read and digest)
- Course Software (how to install the software for this course on your own computer)
- Code Style Guide (guidelines for commenting and code style)
- Problem-Solving Strategies (a general overview of the problem-solving approach we recommend in this course)
- Tips for Debugging (how to fix issues in your code, especially when you get stuck)
- The Rules of Python (a formal description of how Python works at a detailed level)
- The Case-by-Case Method of Recursive Problem Solving describes one approach to breaking down recursive problems to make them easier to solve.
- Weekly Material (longer options that come with chapters or segments that you can follow week-by-week)
Extra Programs
clearNotebook.py
(right-click and select 'save as' to download) This program can be used to clear outputs in a notebook that has been corrupted because an infinite loop printed too much stuff. Simply place the script in the same folder as the corrupted notebook (the file that ends in.ipynb
), open it with Thonny, and run it. It will ask some questions and then clear the notebook. Afterwards, you may want to delete the backup it created if everything looks good, since a corrupted notebook file often takes up a lot of space.
Reference Pages
If you're looking for the details on how a specific function or programming construct works, we have detailed reference pages that should have short explanations for everything you'll use in the course. If something is missing, don't hesitate to ask a question about it. You can follow that link or use the "Quick Reference" link under the "Reference" section of the navigation bar for this site.
Short Explanations
These materials are like blog posts or tutorials for specific aspects of the course. If you're having trouble understanding the specific concepts they relate to, they may prove helpful to consult. They cover the following topics:
- Course Software
- Code Style Guide
- Problem-Solving Strategies
- Tips for Debugging
- The Rules of Python
- The Case-by-Case Method of Recursive Problem Solving
Course Software
Our software page covers how to install all of the required programs for this course on your own laptop. These will also be available on lab computers in the computer labs on campus.
Code Style Guide
If you are wondering how to use comments in your code or generally how to handle issues of code style, we have a code style guide which covers those issues in detail.
Problem-Solving Strategies
Note: you can listen to an audio recording of this material as part of our "The Path to Programming" podcast.
The title of this course is "Computer Programming and Problem Solving," and in large part we are teaching you to solve problems by experience. Practical experience writing code will sharpen your instincts and help you solve all kinds of problems, but even when solving problems from experience, there is a specific set of steps to follow, which we've outlined below. Also, there are a few other general problem-solving skills that we'll talk about, like incremental problem solving and the divide-solve-combine approach.
Problem Solving Steps
-
The first step is to understand the problem. Read the problem statement carefully, whether you're working on a quiz question or a project task. Then, reformulate the problem in your own words. If you're working on a quiz, you can just imagine these words; when working on a project task you should write down your understanding of the problem in your code file, either as comments, or if you are writing a function, as the documentation string for that function. Research shows that skipping this step is one of the biggest causes of problems, but those problems don't show up until later in the problem-solving process, so it also can cost a huge amount of time. Note: your description of the problem should include at least one and ideally several concrete examples of what the program is supposed to do in a particular situation.
-
The second step is to identify similar problems that you already know how to solve. These can be problems from lab, or lecture notebooks, where you've gone over the solution and you know how it works. These won't be exactly identical, and the more dissimilar they are, the more work you will have to do to adapt a solution in the later steps. However, this is the key step that allows you to solve the problem: by understanding how it's like another problem you've already solved, the main thrust of the answer will become clear to you.
-
The third step is to plan out a solution, based on the similar problem you identified in step 2, but adapting that solution to meet the requirements of this problem that you understood in step 1. Whether you're working on a quiz or on a project, you should write down your plan as a series of comments in your answer. These comments (in English, not as code) will form the outline of your solution. It will take some practice to understand the right level of comments to write at this stage, but think of it like outlining an essay: you want to hit the big points, but leave the details for later. One way to think about this step: imagine you are asked to solve the problem as a human, rather than trying to program a computer to do it. What steps would you take? How could you write down those steps as instructions so that another person could do the job based on those instructions? By the end of step 3, you should have both a description of the problem and an outline of a solution written down, but you haven't written any code yet. Again, skipping this step may seem like it will save time, but on average it will cost you a huge amount of time. Also, on a quiz you can often get partial credit if you have included comments describing a correct strategy, even if your implementation of that strategy has errors in it.
-
Step four is where we start to write code. Based on your outline, you are writing a first draft of your solution. It's just a draft, so it's okay if it's messy and incomplete. The point is to put down some code that follows your outline from step 3. During this step, you will often realize that you forgot something in step 3, in which case you should add a comment explaining the extra step that's necessary as you write the code. This step is really hard, because you're suddenly being asked to deploy all of your memorized knowledge of a programming language, including vocabulary (which functions and operators to use and what do they do) and grammar/syntax (where do you put the parentheses or colons, etc.)! This is something that you'll naturally get better at with practice.
-
Step five is to test your program. You've finished a draft, but of course you still need to proofread it and polish it up! Your first draft probably has many errors in it, but one skill that you're building is how to quickly spot and fix those errors based on the feedback that your programming language gives you. Being a good programmer is not about never making mistakes, just like being a good writer is not about never making a tpyo! Instead, you want to become skilled at using the tools available to you to quickly find and fix the mistakes that you will inevitably make, and the first part of that process is to find your mistakes. At first, simply running the program will probably produce an error message, but as you weed out some of the earlier bugs, you'll run out of error messages. At that point, use the concrete examples that you developed in step 1 as points of comparison: run your program using the same inputs, and see if you get the result that you said you should expect. In some cases, you might have made a mistake in part 1, and you can revise your examples (it's hard to see exactly how the program will work before you've started writing it). In other cases, you'll find that your draft program doesn't do the right thing, even though there's no error messages any more. If you test your program and it works for all of the examples you can think of, then you're probably done (but try to think of some extra complicated examples first).
- Step six is to fix your program, now that you've tested it. You will
first need to deploy debugging skills during this step to
refine your understanding of why your program doesn't work, so that
you can figure out how to modify it. If you're getting an error
message, you may still need more information about what's going wrong.
If you don't have an error message but your program's behavior isn't
correct, it's even more important to understand why so that you can
apply the correct fix, instead of making a guess and potentially
making things worse! You should use at least the most basic technique
during this step: add
print
function calls to your code so that it reports key extra information as it runs, and look at what it spits out to figure out what's going on. Add as manyprint
s as you need to get a good picture of what's happening. You could also use the debugger to run your code step-by-step. In any case, when you've identified what's causing the problem, modify your code to fix it. Sometimes at this point, you'll have to go back a bit in the process, even as far back as step 1. Maybe it becomes clear to you that you misunderstood the problem description, for example, or maybe you realize that in step 2, you misidentified which other problems you had already solved were similar. Back up as far as you need to and proceed again, at the very least repeating step 5. But don't feel too bad about that: your final program will be better as a result of your revisions, and you're also learning from your mistakes (you'll learn more from making a mistake and fixing it than you will from getting something right the first try). Even if you have to throw away some work, the knowledge you gained from that attempt will help you in your next attempt and when solving future problems!
If you have tested your code in step five and found that it finally works, congratulations, you're done! One wrinkle is that on a quiz, you won't be able to do steps 5 or 6 for real, because you can't run your code. However, you should be learning how to simulate code and imagine what it will do over the course of this class, so you can do steps 5 and 6 that way. We also usually try to keep the quiz questions simpler so that there's not too much to manage.
Incremental Problem Solving
You might have noticed that the problem solving steps above are a bit unwieldy to apply to an entire project task! Although writing down an outline of the steps you want to take is helpful for keeping yourself on track, there's so much to do that when it comes to steps 5 and 6, things can get a little bit overwhelming. One problem solving approach to apply in these cases is called incremental problem solving, and it basically says that you should only solve a little bit of a problem at a time. You'll still start with steps 1–3 above, but in step 4, instead of trying to write code to complete your entire outline, just write code to do one or two of the steps from your outline.
At this point, you'll need to look at your examples from part 1, and come up with intermediate expected results. What should be true after the first few steps of your outline, for the specific inputs or examples that you had in mind? Write these things down as comments, and then proceed to steps 5 and 6 for your partial program, testing the code that you've got so far to make sure it works correctly, even though it's not really solving the whole problem. Once you've finished the revision process for the first few steps you took, return to step 4 for the next few steps from your outline, and repeat this process as many times as it takes to complete your program. At every step of the way, you should be able to test things and build confidence that the code you've written so far works correctly, so that when you're writing code for the next step, you don't have to second-guess yourself. Occasionally you'll find you have to revisit some of that earlier code and revise it further, but this shouldn't be that common.
It definitely takes skill and practice to use this incremental technique, but it can help to break a too-big problem down into more manageable chunks, although see the next section for another technique that can help in a similar way.
Divide-Solve-Combine
This approach is similar to the incremental approach, but a bit more deliberate, and it involves changing the nature of your solution instead of just the process taken to construct that solution. Of course, by doing so, it often results in more modular and reusable code, which is a good thing. The divide-solve-combine approach, like the incremental approach, is useful when faced with a problem that feels too big or complicated to solve all at once, and it can also be useful when you get stuck on a single step of a larger problem that might have seemed simple when you were building your outline, but that turns out to be tricky when it's time to write code.
The essence of this technique is to divide your problem into two or more separate parts, such that solving those parts individually will solve the whole problem with just a little bit of glue to combine the individual solutions. Like the incremental approach, it takes skill and practice to learn how to apply it well, but it's a quite useful and general technique. The steps are as follows:
-
Identify that your problem is too big to solve all at once, or that you've reached a complex sub-problem of a larger problem you were trying to solve.
-
Decide how to cut up the larger problem: which parts are mostly independent of each other, and if they were solved individually, how could their solutions be combined to solve the larger problem? In some cases, this step is quite hard. Write down your plan for dividing up the larger problem as comments in your code.
-
Reformulate your smaller parts as individual problems, and write down how you plan to combine their solutions. Then, apply the full set of 6 problem-solving steps to each sub-problem one at a time, starting from describing what the problem is and providing examples of how it should work, and finishing up once you've gone through several rounds of testing and revision and you're confident your solution to the sub-problem works. Repeat this for each of your sub-problems.
- Based on your ideas from step 2 about how to combine the sub-problem solutions, write the code necessary to do that, and follow steps 5 and 6 of the general problem solving approach to test and debug your combined solution. It's possible that at this point you may have to revise one of your sub-problems a bit, but you can go back and forth between the larger problem and the sub-problems until things come together.
Although this approach might sound like extra work (I had one problem to solve and you're telling me to create two!?!), it comes with two important benefits. First, it reduces your cognitive load: by dividing the original problem into smaller, simpler problems, you'll reduce the amount of information you need to hold in your brain at once, and especially while you're still exercising to improve the memory structures you'll need when programming, this is a huge benefit. Second, the code you end up with will be easier to understand, easier to debug, and more modular, meaning that it's more likely to be re-usable in the future.
Tips for Debugging
This document lists a few different simple debugging techniques.
Debugging as a Murder Mystery
Are you an expert at solving murder mysteries? Thankfully, you can put that expertise to use in programming as well! Here's how to solve a problem when Python is giving you an error message but you're not sure why:
- What is the murder weapon? Read what the error message says, and try to figure out some hints about which operation actually caused the error, and which variables/values were involved. Try to identify the specific operation (e.g., function call, operator, variable assignment, etc.) that caused the problem.
- Who are the suspects? Identify every variable and value on the
line where the error occurs. For each suspect (i.e., variable or
value) follow these steps:
- Check if the suspect is really a person, and not an elaborate ruse. Did you misspell a variable name? Have you used the correct syntax for defining a value? Did you use leave off quotation marks when you meant to use a string?
- Check if the suspect is wearing a disguise or using an assumed
name. First, come up with an expectation for the type of each
value, and for both the type and the value of each variable. Then,
add a
print
function call to your code to print out what the actual types/values are (add thisprint
immediately before the line where the error occurs). If there's a value or variable whose type or value doesn't match your expectations, you may need to investigate further. - For suspects of interest check how they entered the crime scene. For each mismatched variable from the previous step, identify where its value was most recently updated, and figure out how to get it a more appropriate value. You may also need to change its name to match its value if the value is something that you do in fact need to use.
- If at this point, the perpetrator is still unclear, you may need to fully reconstruct the crime scene step-by-step. Take apart the expression where the error occurs and turn it into a series of single-operation statements using intermediate variables. With only one thing happening at once, the error should be easier to pinpoint.
Rules of Python
To help you understand how Python works, this section explains the rules that Python follows when running your code. Note that as we cover more advanced topics, we will teach you about new rules, but the basic rules are quite simple.
Core rules
When you press the "run" button in Thonny to run a file, or the "run" button in a Jupyter notebook to run a cell, here are the rules that Python follows:
- Start at the very first line of code.
- When running a line of code, first simplify any expressions on
that line. To simplify an expression, Python simplifies things one
step at a time, and the possible simplification steps are as follows:
- Replace a variable name with the current value of that variable.
- Combine two values using an operator. The two values to be combined must already be fully simplified.
- Replace a function call whose argument(s) have been completely simplified with the result of that function call. Note that during this step, the function being called may produce side effects. Note that each built-in function has its own rules for what the result will be (and for what side effect(s) will occur) based on the argument(s) you give it.
- Once all expressions have been fully simplified down to individual values, if the line of code is an assignment statement, the value of the variable named in the assignment statement will be updated. If that variable already existed, its old value will be forgotten, or if not, that variable will be created. Either way, the simplified value of the expression on the right-hand side of the equals sign becomes the new value of the variable named on the left-hand side of the equals sign.
- After all expressions have been simplified into values, and an assignment has been made (if there was one) Python moves on to the next line of code in the file or notebook cell and repeats this process. When the last line of code has finished executing, the program stops.
Additional notes:
- If you are running code in a notebook cell and the last line of that code is not an assignment statement, Jupyter will create an "Out []" box to display the value of the expression on the last line of code.
- If you are typing code in the Thonny shell, as soon as you press "enter" Python will execute the line of code that you typed according to the rules above, but like in the notebook, it will also display the fully-simplified value if that line of code was an expression and not an assignment statement.
- For both of the special cases above where values are displayed, nothing
will be displayed when the simplified value of the expression is
the special value
None
.
Tips for programming
Based on these rules, here are some important ideas to keep in mind:
- Usually, your goal in a project or exercise will be to either store a specific value in a variable, or more often, to produce a certain series of side effects (for example, a particular series of printed messages).
- If a line of code just contains an expression and it is not an assignment statement, then that expression should normally involve at least one function which produces one or more side effects. Otherwise (if there are no side effects and you are not storing the result in a variable), that line of code is redundant and can be removed (so you've probably done something wrong).
- As a corollary to the above, every line of code should be an assignment statement unless it contains a function call that has side effects.
- Of the functions we have learned about so far, here is the list of
functions that have side effects:
print
(side effect: displays output)input
(side effect: displays a prompt, and pauses until input is given. Note thatinput
also has a result value, which is the string of text that was typed after the prompt.)- The
turtle
andturtleBeads
drawing functions each have a side effect of moving the turtle and/or adding to the drawing in progress.
- Note that the conversion functions
int
,float
, andstr
as well as theround
function are not on the above list: they do not have side effects. Instead, their result is the converted value, and to use them properly, we generally want to store that result in a variable.
Rules for functions
The def
statement adds to the core rules above in the following ways:
-
In rule #2, for running a line of code, if that line of code is a function definition (i.e., if it starts with the keyword
def
), instead of applying the normal simplification/assignment process, Python does the following:- It gathers all of the lines of code which are indented at the
same level as the first line of code following the
def
line (including that first line of code). - Without simplifying anything or running any of that code, Python
stores that code into a box (just like variable assignment) and
names that box according to the function name which appears after
the
def
keyword. Python also remembers the parameter names and the order of parameters which are specified on the definition line. - Python then proceeds to execute the next line of code that comes
after all of the indented code that it collected; that line of
code must match the indentation level of the
def
statement, or anIndentationError
will occur.
- It gathers all of the lines of code which are indented at the
same level as the first line of code following the
- In addition to the above process for gathering and storing code,
rule #2 part 3 now includes the idea of simplifying a function call to a
custom function that's been defined using
def
. When simplifying a custom function call, we follow the following rules to figure out the result value which will replace the function call in the expression we're simplifying:- First, Python creates a new function call frame for processing the custom function, which is a special zone that can store temporary variables which will only be available during the processing of that function.
- Second, Python takes each argument value from the function call that we want to simplify, and based on its order among the arguments, it figures out which parameter of the function it is calling that argument corresponds to. For each of these parameters, an assignment is made within the new function call frame that assigns that parameter to hold the associated argument value.
- Next, Python executes each line of code that was stored when the function was defined, according to all of the normal rules for running code. During this process, any assignments that are made create or modify variables that are in the current function call frame, although variables from the whole program context can still be used as part of an expression (they just can't be modified).
- If Python encounters a
return
statement (a line of code that starts with the keywordreturn
) it first fully simplifies the expression that follows thereturn
keyword (if there is one), and then the simplified value of that expression becomes the result of the function call (no further lines of code will be executed). If there is no expression after thereturn
keyword, then the result value will be the special valueNone
. - If there is no
return
statement, when the last line of code in the stored function is completed, the special valueNone
becomes the result value.
Notes:
- An attempt to assign a new value to a variable defined outside the current function call frame will simply create a new separate variable with that same name inside of the current function call frame, and any future references to that variable within the current function call frame will refer to that variable.
Rules for conditionals
The if
statement adds to the core rules above in the following ways:
- In rule #2, for running a line of code, if that line of code is a
conditional (i.e., if it starts with the keyword
if
), instead of applying the normal simplification/assignment process, Python does the following:- It gathers all of the lines of code which are indented at the
same level as the first line of code following the
if
line (including that first line of code). - If simplifies the condition part of the conditional (the
expression between the
if
and the colon at the end of the line) and determines whether that simplified value is "truthy" or "falsey" (see below). - If the condition's simplified value is truthy, the lines of code that were collected in step 1 are executed per all of the usual rules of Python (including these rules). However, if the simplified condition value is falsey, those lines of code are skipped.
- If the line of code following the indented block is just
else:
, then the indented block of code following thatelse
will be skipped if the first block of code was executed, or executed if the first block of code was skipped (the two blocks are mutually exclusive). If there are multipleelif
blocks above anelse
, theelse
is only executed if all of them are skipped. - If the line of code following an
if
(orelif
) block starts withelif
, the condition on that line will be simplified only if all connectedif
andelif
blocks above it were skipped, and that condition's truthy/falsey status will determine whether we execute or skip the block underneath it.
- It gathers all of the lines of code which are indented at the
same level as the first line of code following the
For the purposes of conditional choices, "truthy" and "falsey" values are defined as follows:
- The boolean value
True
is truthy and the valueFalse
is falsey. None
is falsey.- The numbers
0
and0.0
are falsey; all other integers and floating point values are truthy. - Empty strings (strings of length 0; strings with spaces in them aren't considered empty) are falsey, and all other strings are truthy.
- Empty lists (and most empty data types) are falsey, and non-empty lists are truthy, even if they contain only falsey values.
- Empty ranges are falsey, but any range that includes at least one number is truthy.
Rules for loops
The while
and for
statements add to the core rules above in the
following ways:
-
In rule #2, for running a line of code, if that line of code is a while loop (i.e., if it starts with the keyword
while
), instead of applying the normal simplification/assignment process, Python does the following:- It gathers all of the lines of code which are indented at the
same level as the first line of code following the
while
line (including that first line of code). This is the loop body. - It simplifies the condition expression which follows the keyword
while
(this is the loop condition). If the simplified value of that expression is truthy, the loop body is executed using all of the normal rules for executing code, including these rules about loops. Otherwise, the loop body is skipped and execution continues after it. - If the loop body was not skipped, when it is finished
(assuming it was not interrupted by something like a
return
) the loop condition is simplified again, and if it still simplifies to a truthy value, the loop body is run again. This process continues until the loop condition simplifies to a falsey value, at which point the loop body is skipped and the loop ends. If the loop condition never becomes falsey, the loop will continue indefinitely.
- It gathers all of the lines of code which are indented at the
same level as the first line of code following the
- In rule #2, for running a line of code, if that line of code is a
for loop (i.e., if it starts with the keyword
for
), instead of applying the normal simplification/assignment process, Python does the following:- It gathers all of the lines of code which are indented at the
same level as the first line of code following the
for
line (including that first line of code). This is the loop body. - The
for
line must name a loop variable, followed by thein
keyword, and then the loop expression. Python simplifies the loop expression once, and the result must be a sequence (which we call the loop sequence). Note that the loop expression is simplified only once, unlike the loop condition in awhile
loop. - Once the loop sequence has been determined, Python assigns the
first item in the loop sequence as the value of the loop
variable and then executes the entire loop body following
all of the normal rules of Python, including these ones. When the
loop body is finished (as long as it was not interrupted, e.g.
via
return
), Python will assign the second item from the loop sequence into the loop variable and execute the loop body again, repeating the entire process for each of the items in the loop sequence. (If the loop sequence is an empty sequence, then the loop body is never executed). Each execution of the loop body is called an iteration. - Once all iterations of the loop have finished, execution continues with the code that comes after the indented loop body.
- It gathers all of the lines of code which are indented at the
same level as the first line of code following the
The Case-by-Case Method for Recursive Problem Solving
This case-by-case explanation page describes a method for solving recursive problems that breaks things down to make it easier to get started if you're stuck.
Weekly Materials
Think Python
Allen Downey's Think Python (second edition) is our textbook for this class. You can read ThinkPython on the web or download a free PDF version of the textbook.
There is also a free interactive version of the textbook available on Runestone Academy. You can access the textbook without creating an account there, or create a free account to track your progress on the assignments, but note that those assignments do not count for credit for this course!
Our lecture and project pages also include links to relevant chapters on the web.
While reading the textbook is not required, we recommend it if you want to build a deeper understanding of the material, or if you are feeling lost about some of the concepts in the class. It does a good job of describing things systematically.
The Path to Programming
As an additional resource for the class beyond the textbook, we have a podcast that covers course topics at a high level, titled "The Path to Programming." This series gives advice about how to approach the class and talks about the concepts we're covering, but it doesn't get too much into the details of how to write code: the textbook, lecture slides, notebooks, and labs handle that.
Listening to these recordings isn't mandatory, but they are designed to be helpful in terms of understanding the concepts and approaching the class, and they're not that long each week.
Note: Each entry includes controls to play directly in the browser, a download link for the audio file if you want to listen to it later, a download link to the script if you'd prefer a text format, and an expandable widget that shows the script in the page.
Unit 1: Getting Started
-
"What is Programming?" (3:26)
Explains what programming is and what programmers do.
Click here to download 00_what_is_programming.mp3
Click here to download 00_what_is_programming_script.txtShow the script
- This first segment is devoted to an important question: "What is programming?" - Programming is craft, art, engineering, and maybe even science. - But one way we can approach this question is to ask: what does a programmer do? - Someone who is programming writes programs by putting together words in a programming language, which begs the questions: "What is a program, and what is a programming language?" - A program is a series of instructions for a computer to carry out. They're written down in a way that the computer can execute them automatically, using a programming language. - Depending on the language and the computer, the instructions could have all sorts of effects, like doing calculations, displaying patterns on a screen, searching for information on the web, moving a robot arm, or transferring money between bank accounts. - So a program specifies some behavior or a series of actions to carry out, and the computer follows a program (we call this 'executing' it). - Does that give us an answer to our question "What is programming?" - Here's one definition: - Programming is a process of crafting programs, which are lists of instructions for a computer to carry out. - So what do we need to do to learn how to program? - We'll need to learn the language of the computer to make sure we can write down our instructions in a way that the computer can understand, and then we'll need to learn about processes and procedures. - A process is just a sequence of events or actions, and a procedure is a more general word than "program" for a series of instructions to be carried out (a procedure might be carried out by a person or an institution, not just by a computer). - So a procedure is a recipe for a process: if you follow procedure X, that will create process Y. And processes are designed to result in certain outcomes. - For example, a recipe is a kind of procedure; if you follow it you will carry out a process that might result in something delicious you can eat. - Similarly, a program is a kind of procedure, if you tell a computer to follow it, you can get that computer to engage in a process, and that process can achieve all sorts of things. - As you get more and more comfortable with programming, you'll be learning the secrets of a programming language, but that's only half of the goal: once you learn how to communicate with the computer you'll also need to learn what to say, and in particular, how to create procedures that result in useful processes. - For this reason, learning to program has a lot in common with learning how to design a board game or learning how to manage a bureaucracy: in all three pursuits, a deep understanding of how procedures shape processes and how processes can be manipulated to achieve desired outcomes is critical. - For the same reason, programming has aspects of art, craft, design, engineering, and science: we can approach the job of creating procedures from many different angles, but it's fundamentally a creative process that's got some tricky constraints, like architecture. - So back to our original question: "What is programming?" - Programming is crafting procedures for computers, using a programming language, with the goal of creating processes that achieve particular results. - Now that you've thought a bit about procedures, processes, and programs, keep them in mind as you dive into your first steps of programming practice. - You're going to be learning a few things at once, and it helps to keep them straight!
-
"Learning Strategies" (11:21)
An overview of what you'll learn in this class, including strategies for problem solving and advice for approaching the class.
Click here to download 01_what_to_learn.mp3
Click here to download 01_what_to_learn_script.txtShow the script
Hello! - Welcome to the Path to Programming; the audio supplementary materials for introduction to computer science! - I am a former student that took this introductory course and today I want to talk to you about the skills you need to make the best of this class. - Learning computer science can be challenging for many reasons. It’s almost like transporting yourself back to elementary school to learn math or writing for the first time because the concepts are new and you’re going to be expressing them in a way that is probably not familiar to you. So you really want to familiarize yourself with the programming language. - In this class you will be using Python, but this goes for any programming language. An easy way to start familiarizing yourself with Python would be to memorize the available commands. - Every programming language has a vocabulary of built-in commands that you'll need to learn to use, because you will be using them very often. The built in functions that you might end up needing are: max (finds the of the several items that has been passed into the parameter), min (finds the smallest number that has been passed into the parameter), int (takes any number, or a piece of text that spells out a number, and gives back an integer), float (takes an integer or string that spells out a decimal number and gives back a floating-point number), len, str, round and print, input (Entering a print statement and the user can enter an answer) and more! Make sure you understand what each of these built-in functions do and make sure you know when to use them. - For example you could use max along with len to find the length of the longer of two pieces of text. - We will get more into the specific uses of the functions but what’s important for now is that you know what these built in functions are called and what each function does briefly. Understanding the built in functions ties into understanding data types and what operations to use with them. - A data type is something every value in python has. It basically describes what kind of Knowing the type of data can help you choose the right operator. - There are four basic operators in Python these are +(plus), -(minus), %(remainder), *(times) and /(divide). - They don’t just act like the mathematical operators we know, because they interact with different types of data differently. - For example the plus operator can be used to concatenate (combine) strings. - One thing that I didn't pay enough attention to in the first few weeks of learning how to code was the memory model. The memory model demonstrates how a program would run and how assignments happen when you declare a variable. The memory model explains how the computer works when your program runs. - The first few weeks it seems really trivial to use the memory model but this is actually the perfect time to get acquainted with it. It’s important to use the memory model because programming has a lot of variable assignments that occur. - Another skill that you'll need to build up is working memory to hold several variables in your mind at once and understand how a sequence of several instructions will operate on them. Understanding your variables and what values they hold can help you understand how your code runs as well. - But variables aren't the only thing we use in Python. We can also just write expressions to calculate values, and we don’t need to assign them to a variable. The reason we use variables is to make sure that they are stored in the memory, so that we can access them later on without having to write the whole statement over again. - And obviously understanding what you’re doing with each line of code is one of the most essential parts of programming. There are so many things you will learn throughout introduction to programming and understanding what each function does, whether you define it or it’s a built in function is essential for you to be able to write code that not only works but is also efficient. - Everything we talked about so far is more so on the side of understanding the basics of programming. - We touched on understanding the programming language, important features of the language include built in functions and user defined functions. - If you really get to know the functions then you will know which operations to use with them. - Another thing we touched on was making sure that you understand each variable you declare, know how to follow the statements you are making and an easy way to do this is by using the memory model. - But coding is not just about the programming language you use, it’s also about you, the user, and how hard you work beyond the computer screen. - An essential part of learning how to code is having good teamwork skills, including the ability to ask questions about what you don't know, and the ability to answer questions gracefully and learn from the process. - The biggest advice I can give you as someone who previously took introduction to programming is to never be afraid to ask questions. It’s easy to think that the answer to your question is obvious, or that it is not the most complex question of all time. But those things do not matter, if you are curious about it and you have the opportunity to ask it, never pass up on it. That’s why your instructors are there for you, they want to answer all your questions no matter how big or how small. - Learning something from scratch is always hard, so never doubt the validity of your questions. The more questions you ask the easier it will become for you to answer the questions that you or others have. - Beyond asking questions a very important part of intro is team work. Working in a group is often a great opportunity to see the way other people view the process of coding. You can always learn something from your partner or teach something to your coding partner without even realizing it. - Maybe the way you think about the memory model is different then your coding partners and you can really help them understand things more clearly with how you think about it. Or maybe your partner is really efficient about when they use their variables after executing a bunch of statements. - An important point to remember is not everyone is at the same level even if it is an introductory class, so never feel discouraged if your coding partner has more experience, or has a different approach then you. At the same time, if you end up feeling like your partner doesn't understand things, instead of trying to go ahead and solve things on your own, take the time to explain things to your partner. - The best way to learn something is to teach it, and in the process, you'll find that you will be able to build more solid foundations for your own understanding, even if you are explaining a concept that you feel is pretty "basic." Finally what will help you the most during this class is to have strong planning habits (for example, writing documentation and comments before writing code). - Commenting is often a part of programming that the user can easily neglect because when you understand a problem and how to solve it you often don’t feel the need to explain how you've gotten there. But not everyone has the same thought process or problem solving process, which is why it is very important to describe exactly what you are doing, so that the purpose of your code is understandable in every way possible. - As a plus, explaining your process and plan using comments and documentation before you write your code will help you reach a correct solution more quickly and will help make sure you understand the problem that you're trying to solve. - Besides having generally good planning skills make sure that you have the most clear and effective approach, by applying the key case based problem solving steps. The problem solving steps are simple and they include: 1. Before attempting to solve a problem you really have to understand what the problem is asking for. 2. Before trying to code something from scratch, think of a way to solve the problem and how you would approach it yourself if you didn't have a computer. That's the hard part, figuring out how to solve a complex problem, the easier part is telling the computer what to do in order to solve that problem. 3. If you’re struggling to solve the problem on your own, gather relevant examples that can help you. If there’s a similar problem that you solved in class go over what the idea behind it was and look at the code to see how those ideas were implemented in the code. - Don’t only look for the similarities of the current and previous problems but also look for differences and try to understand where these differences are coming from. This is why understanding the built in functions, and understanding variables is important because you as the programmer will determine what tools you need to solve the problem. The more you understand the functions the easier it will be for you to ‘diagnose’ what you need. This way it will become easier for you to propose a solution to the problem. 3. Program your solution (Write down the instructions in computer code. You'll need to exercise your knowledge of a programming language to understand how to translate your steps into steps the computer can carry out.) 4. Test your program to make sure it works (Use your examples from step 1 and see if the program behaves correctly.) 5. Fix your program (If your program doesn't work, or only work sometimes, first figure out exactly why, and then decide which step you need to revisit. - Sometimes you just need to tweak, other times you need to go back to step 1. But don't worry, your incorrect work isn't wasted: it has already helped you build a deeper understanding of the problem that you're working on.) - If you can follow these problem-solving steps in order, you should be able to solve a wide range of different problems, and as you learn more and more about specific functions and language constructs, you'll be able to expand your vocabulary and keep solving more and more difficult problems. But if you develop bad habits and try to jump straight to a solution, you may find yourself getting stuck a lot or spending a huge amount of time to solve problems as they get more complex. - Pay attention to all of the basics we've discussed here and the process of learning how to program should go smoothly!
-
"Problem-Solving Strategies" (13:22)
Talks about key problem-solving strategies for this course, covering the same material that's on our problem-solving strategies reference page.
Click here to download 02_problem_solving_strategies.mp3
Click here to download 02_problem_solving_strategies_script.txtShow the script
- This segment talks about several key problem-solving strategies that you'll be learning about in this class, and it's useful for you to know what these problem-solving strategies are, before you begin. - The title of this course is "Computer Programming and Problem Solving," and in large part we are teaching you to solve problems **by experience**. Practical experience writing code will sharpen your instincts and help you solve all kinds of problems, but even when solving problems from experience, there is a specific set of steps to follow, which we've outlined below. - Also, there are a few other general problem-solving skills that we'll talk about, like incremental problem solving and the divide-solve-combine approach. - Let me talk first about the problem-solving steps. 1. The first step is to **understand the problem**. - Read the problem statement carefully, whether you're working on a quiz question or a problem set task. Then, reformulate the problem in your own words. - If you're working on a quiz, you can just imagine these words; when working on a problem set you should write down your understanding of the problem in your code file, either as comments, or if you are writing a function, as the documentation string for that function. - Research shows that skipping this step is one of the biggest causes of problems, but those problems don't show up until later in the problem-solving process, so it also can cost a huge amount of time. - Note: your description of the problem should include at least one and ideally several **concrete examples** of what the program is supposed to do in a particular situation. 2. The second step is to **identify similar problems** that you already know how to solve. - These can be problems from lab, or lecture notebooks, where you've gone over the solution and you know how it works. - These won't be exactly identical to the one you're solving now, and the more dissimilar they are, the more work you will have to do to adapt a solution in the later steps. - This is the key step that allows you to solve the problem: by understanding how it's like another problem you've already solved, the main thrust of the answer will become clear to you. 3. The third step is to **plan out a solution**, based on the similar problem you identified in step 2, but adapting that solution to meet the requirements of this problem that you understood in step 1. - Whether you're working on a quiz or on a problem set, you should write down your plan as a series of comments in your answer. These comments (in English, not as code) will form the outline of your solution. - It will take some practice to understand the right level of comments to write at this stage, but think of it like outlining an essay: you want to hit the big points, but leave the details for later. - One way to think about this step: imagine you are asked to solve the problem as a human, rather than trying to program a computer to do it. What steps would you take? How could you write down those steps as instructions so that another person could do the job based on those instructions? - By the end of step 3, you should have both a description of the problem and an outline of a solution written down, but you haven't written any code yet. - Again, skipping this step may seem like it will save time, but on average it will cost you a huge amount of time. - Also, on a quiz you can often get partial credit if you have included comments describing a correct strategy, even if your implementation of that strategy has errors in it. 4. Step four is where we start to write code. - Based on your outline, you are writing a first draft of your solution. It's just a draft, so it's okay if it's messy and incomplete. The point is to put down some code that follows your outline from step 3. - During this step, you will often realize that you forgot something in step 3, in which case you should add a comment explaining the extra step that's necessary as you write the code. - This step is really hard, because you're suddenly being asked to deploy all of your memorized knowledge of a programming language, including vocabulary (which functions and operators to use and what do they do) and grammar/syntax (where do you put the parentheses or colons, etc.)! - This is something that you'll naturally get better at with practice. 5. Step five is to test your program. - You've finished a draft, but of course you still need to proofread it and polish it up! Your first draft probably has many errors in it, but one skill that you're building is how to quickly spot and fix those errors based on the feedback that your programming language gives you. - Being a good programmer is not about never making mistakes, just like being a good writer is not about never making a tpyo! Instead, you want to become skilled at using the tools available to you to quickly find and fix the mistakes that you will inevitably make, and the first part of that process is to find your mistakes. - At first, simply running the program will probably produce an error message, but as you weed out some of the earlier bugs, you'll run out of error messages. - At that point, use the **concrete examples** that you developed in step 1 as points of comparison: run your program using the same inputs, and see if you get the result that you said you should expect. - In some cases, you might have made a mistake in part 1, and you can revise your examples (it's hard to see exactly how the program will work before you've started writing it). - In other cases, you'll find that your draft program doesn't do the right thing, even though there's no error messages any more. - If you test your program and it works for all of the examples you can think of, then you're probably done (but you should try to think of some extra complicated examples first). 6. Step six is to fix your program, now that you've tested it. - You will first need to deploy [debugging skills](debugging) during this step to refine your understanding of why your program doesn't work, so that you can figure out how to modify it. - If you're getting an error message, you may still need more information about what's going wrong. - If you don't have an error message but your program's behavior isn't correct, it's even more important to understand why so that you can apply the correct fix, instead of making a guess and potentially making things worse! - You should use at least the most basic technique during this step: add [`print`](builtins#print) function calls to your code so that it reports key extra information as it runs, and look at what it spits out to figure out what's going on. Add as many `print`s as you need to get a good picture of what's happening. - You could also use the debugger to run your code step-by-step. - In any case, when you've identified what's causing the problem, modify your code to fix it. - Sometimes at this point, you'll have to go back a bit in the process, even as far back as step 1. Maybe it becomes clear to you that you misunderstood the problem description, for example, or maybe you realize that in step 2, you misidentified which other problems were similar. - Back up as far as you need to and proceed again, at the very least repeating step 5. - But don't feel too bad about that: your final program will be better as a result of your revisions, and you're also learning from your mistakes (you'll learn more from making a mistake and fixing it than you will from getting something right the first try). - Even if you have to throw away some work, the knowledge you gained from that attempt will help you in your next attempt and when solving future problems! - If you have tested your code in step five and found that it finally works, congratulations, you're done! - One wrinkle is that on a quiz, you won't be able to do steps 5 or 6 for real, because you can't run your code. - However, you should be learning how to simulate code and imagine what it will do over the course of this class, so you can do steps 5 and 6 that way. - We also usually try to keep the quiz questions simpler so that there's not too much to manage. - Those are the six steps to solving a problem, and of course step 6 involves repeating some of them, so it may take longer than just getting to step 6. - Now I'm going to talk about incremental problem solving, which is another approach that you can merge with that first approach, to make it easier. - You might have noticed that the problem solving steps above are a bit unwieldy to apply to an entire problem set task! - Although writing down an outline of the steps you want to take is helpful for keeping yourself on track, there's so much to do that when it comes to steps 5 and 6, things can get a little bit overwhelming. - One problem solving approach to apply in these cases is called **incremental problem solving**, and it basically says that you should only solve a little bit of a problem at a time. - You'll still start with steps 1–3 above, but in step 4, instead of trying to write code to complete your entire outline, just write code to do one or two of the steps from your outline. - At this point, you'll need to look at your examples from part 1, and come up with intermediate expected results. - What should be true after the first few steps of your outline, for the specific inputs or examples that you had in mind? - Write these things down as comments, and then proceed to steps 5 and 6 for your partial program, testing the code that you've got so far to make sure it works correctly, even though it's not really solving the whole problem. - Once you've finished the revision process for the first few steps you took, return to step 4 for the next few steps from your outline, and repeat this process as many times as it takes to complete your program. - At every step of the way, you should be able to test things and build confidence that the code you've written so far works correctly, so that when you're writing code for the next step, you don't have to second-guess yourself. - Occasionally you'll find you have to revisit some of that earlier code and revise it further, but this shouldn't be that common. - It definitely takes skill and practice to use this incremental technique, but it can help to break a too-big problem down into more manageable chunks, although see the next section for another technique that can help in a similar way. - And that next section is: divide-solve-combine. - This approach is similar to the incremental approach, but a bit more deliberate, and it involves changing the nature of your solution instead of just the process taken to construct that solution. - Of course, by doing so, it often results in more modular and reusable code, which is a good thing. - The divide-solve-combine approach, like the incremental approach, is useful when faced with a problem that feels too big or complicated to solve all at once, and it can also be useful when you get stuck on a single step of a larger problem that might have seemed simple when you were building your outline, but that turns out to be tricky when it's time to write code. - The essence of this technique is to divide your problem into two or more separate parts, such that solving those parts individually will solve the whole problem with just a little bit of glue to combine the individual solutions. - Like the incremental approach, it takes skill and practice to learn how to apply this technique well, but it's a quite useful and general technique. The steps are as follows: 1. Identify that your problem is too big to solve all at once, or that you've reached a complex sub-problem of a larger problem you were trying to solve. 2. Decide how to cut up the larger problem: which parts are mostly independent of each other, and if they were solved individually, how could their solutions be combined to solve the larger problem? - In some cases, this step is quite hard. - You should also write down what you're thinking in this step as comments in your code. 3. Reformulate your smaller parts as individual problems, and write down how you plan to combine their solutions. - Then, apply the full set of 6 problem-solving steps to each sub-problem one at a time, starting from describing what the problem is and providing examples of how it should work, and finishing up once you've gone through several rounds of testing and revision and you're confident your solution to the sub-problem works. - Repeat this for each of your sub-problems. 4. Based on your ideas from step 2 about how to combine the sub-problem solutions, write the code necessary to do that, and follow steps 5 and 6 of the general problem solving approach to test and debug your combined solution. - It's possible that at this point you may have to revise one of your sub-problems a bit, but you can go back and forth between the larger problem and the sub-problems until things come together. - Although this approach might sound like extra work (I had one problem to solve and you're telling me to create two!?!), it comes with two important benefits. - First, it reduces your cognitive load: by dividing the original problem into smaller, simpler problems, you'll reduce the amount of information you need to hold in your brain at once, and especially while you're still exercising to improve the memory structures you'll need when programming, this is a huge benefit. - Second, the code you end up with will be easier to understand, easier to debug, and more modular, meaning that it's more likely to be re-usable in the future. - That's all I have to say on problem-solving techniques; I hope as you move through this class you revisit these techniques and think about how you're applying them when you're working on the problem sets and quizzes.
Unit 2: Defining Functions
-
"Functions" (12:23)
Talks about functions, defining custom functions, and the function call model including function call frames, as well as the difference betweenprint
andreturn
.
Click here to download 03_functions.mp3
Click here to download 03_functions_script.txtShow the script
- Hello! Welcome to the Path to Programming; the audio supplementary materials for introduction to computer science! - I am a former student that took this introductory course and today I want to talk to you about functions! - You might have heard of functions in a mathematical sense, and in a higher conceptual sense functions in programming work in the same way. Just like in math, functions have variables that go in, and a result that comes out. - So a function in computer science takes a certain input (or several inputs) and returns an output based on the input. - Last week we talked about built-in functions, like print, max, min, int and more. These are built-in functions that already exist in Python. - There can be different outcomes from a function: it can have a result, and it could also have one or more side effects. Functions that don't have a result value instead have side effects. - Some of the built in functions we have talked about so far, like print and input, have side effects, namely, displaying text to whoever is running the program, who we call "the user." - One rule of thumb is that if a function only has side effects and no result value, you won't store the result in a variable (because there is no result). - Functions like print fall into this category, and they generally make something apparent to the user, whether that's text, graphics, or audio. - On the other hand, when you use a function like max, min, int, float or str (string) which has a result value, you do need to store the result in a variable. These functions don't have side effects, and their purpose is to generate their result values that some other part of the program will further modify or make apparent to the user. - Basically when you use a function that has a side effect there will be something displayed, but if you use a function that only produces a result, nothing will be displayed unless you store that result in a variable and later use that variable with a side-effect function. - Of course, there are some complicated functions, like input, which have both side effects and results. Input displays text, but also asks the user to enter their own text, and it makes that text available for use in your program as its result value, which is why despite having a side effect, you can store the result of input in a variable. - Now that we know the difference between side effects and result values, let's talk more about functions, but instead of talking about the built-in functions let's talk about user defined functions! - Functions are ways that you can store instructions to be used later, and they're quite powerful. Once you can define your own functions you will be able to perform a variety of different operations that are not in the library of the programming language you are using. - By capturing common patterns you can write so many functions. So let's dive into the nuts and bolts of how you can come up with your own user defined function. - The first thing you must do when writing your own function is to define it! - To do this in Python you would use the def keyword. When you define a function you can name the function whatever you want, but make sure to pick a name that makes sense to everyone else that would use the code you wrote and not just you. - Once you have a name then you may specify one or more parameters. A parameter is basically a slot that you can use to give information to your function when you call it. - Each time anyone calls your custom function, they must supply an argument value for each parameter that you set up when you defined the function. - For example if you define a function with one parameter named 'x,' whoever calls that function will need to supply one argument, and whatever value they supply will be called 'x' within your code. - After defining your parameters, you have to define how your function will actually work, and this is done in the body of your function. - This is the meat of the function and tells the computer what exactly your function will do, and it's made up of Python code statements just like the code you've already been writing. For example if you are writing a square function the body is where you would tell it to multiply the number with itself. - When you call a function, Python executes each line of code that you wrote in the function body, until it reaches a return statement. - If that return statement has an expression after it, Python will simplify that expression and the resulting value will become the result value of the function. - If the return statement doesn't have an expression after it, or if Python reaches the end of your function body without seeing a return statement, the result value of your function will be the special value None, which is Python's way of saying "there's no actual value here." - Either way, whoever called the function will get back the result value, which they can store in a variable or use as part of an expression, just as you've already been doing with built-in functions. - An important thing to pay attention to when writing the body of your function is to indent. - Indentation is a part of Python and tells the computer how to read what you have written: code that shares the same indentation level will be treated as part of the same group, for example, as the body of a function. - If you don't use indentation correctly the computer will get confused, and won't know how to read what you have written. If you don't indent correctly you will get an indentation error so make sure that you are indenting it correctly and consistently! - Last week we also touched on the memory model and how useful it will become and functions are a place where you can use the memory model to really understand what is going on behind the scenes! The application of the memory model to a function is called the Function Call Model. - By following the function call model rules we can figure out the result value of a function. - We already talked about how you can write your own function by using the def keyword, using parameters to accept arguments and specifying what will happen using a function call body. - When you call a function, behind the scenes Python creates something that is called a function call frame. - You can think of the function call frame as a box or special zone that can store temporary variables which will only be available during the processing of that function call. - So this all happens behind the scenes and you don't really interact with the function call frame as a programmer, but Python or the programming language you are using uses the function call frame to be able to execute a custom function without interfering with any other variables that might exist. - The function call frame contains the name of the function, the parameters, each filled with their corresponding argument values; and the body of the function. The function call frame evaluates the body of the function using the arguments that were provided as the value of each parameter, and running every line of code in the function body from the top to the bottom. - The frame is important conceptually because it is not something that you can really see at work when you are coding because it is discarded after the result value is determined and returned. - This means that variables within a function, including its parameters, are thrown away when we get to the end of the function, and they are not accessible within other functions: only the result value is. - Just to go over what we talked about in even more detail, when you define a new function, which you do just once, you set up the parameters and specify what code should execute. - Then each time that function is called, a new function call frame is created so that Python can process that specific function call (which might have different argument values than another function call to the same function). - The function call frame is a special zone where the behind the scenes work takes place with temporary variable reassignments etc. - Eventually, when the function is finished, the function call frame is discarded, and only the result value is returned to the code where the function call was made (which can now continue). - As a concrete example, imagine that you write a function named 'square' with one parameter named 'x,' and a single line of code in its body which read 'return x times x.' - If you call that function by writing 'square parenthesis five close parenthesis', you are providing 5 as the argument value for that function call, and so x will be 5 in the function call frame that is created. - With x assigned to 5, the return expression which was 'x times x' will evaluate to 25. So wherever you wrote your function call, that part of the code will simplify to the value 25. - Note that if there are multiple parameters, there must be the same number of arguments, and each argument is assigned to be the value of one parameter based on the ordering of the parameters and arguments: first with first, second with second, etc. - Now that we know what goes on behind the scenes when you call your function with the function call frame, let's talk about more nitty gritty things. - First we already mentioned that there can be multiple parameters in a function. The function call frame is able to take care of this by matching up each argument value with a single parameter as we mentioned. - Besides having multiple parameters you can also call other functions within a function that you have defined. Calling a function basically means that you can use it in the body of the function that you are currently writing. - The only condition required to call a function is that it either has to be built-in or you must have previously defined it, essentially it must exist before you call a function that uses it (but not necessarily before that other function is defined). - Calling multiple functions can be useful when you are trying to make more complicated calculations. - Another concept about functions that we will touch on is the local variable. A local variable only exists in the body of the function, which is where you define how your function will work in case you forgot! You can not reference a local variable outside of the body of a function. - Parameters are also a kind of local variable. They are assigned a value when the function is invoked (which is another word for calling a function). They also cannot be referred outside the function. - Finally I want to touch in the difference between using a print statement or a return statement in the body of your function. - This concept will tie into fruitfulness which I will touch on more in a minute, but fruitfulness will become very important as you start writing more complicated functions. - A return statement in the body specifies the result of the function invocation whereas a print statement causes characters to be displayed on the screen while your function is running. - Think back to the beginning of this episode when we mentioned that the print statement has a side effect, which displays something on your screen. - Be careful to not confuse print and return statements, as they have different uses. - A return statement creates a result value calculated from the function call frame, and that result gets returned to whoever called the function, so it can be used elsewhere in your program. - On the other hand, a print statement displays text to the user, but this text does not become accessible for further operations in Python. - Typically you will assign the result of a function which has a return value to a variable so that you can use it later on, but if a function just uses print to display text and does not have a return value, you will not really do that. - As we mentioned before if your function does not have a return statement the function will return the special value 'None'. - If a function has a return value other than None than it is called fruitful. - If a function does not have a return value then it is non-fruitful. - For example the print function does not have a return value (as we mentioned it displays text as a side effect) and therefore it is a non-fruitful function. - That was our introduction to functions! - Make sure from this episode you take away the basic ideas of what a function is, how you define a function using a name, parameters and a body and how when you call a function, Python executes it using the function call model. - Once you understand these basics you can think about more complicated scenarios such as a function with multiple parameters, or a function that calls another function. - Finally make sure you understand the difference between a fruitful and non fruitful function. - Thank you for joining me on your path to Programming! I hope your journey is going well.
Unit 3: Booleans and Conditionals
-
"Booleans and Conditionals" (11:08)
Talks about Booleans, comparators, and conditionals, including if, elif, and else statements.
Click here to download 04_booleans_and_conditionals.mp3
Click here to download 04_booleans_and_conditionals_script.txtShow the script
- Hello! Welcome to the Path to Programming; the audio supplementary materials for introduction to computer science! - I am a former student that took this introductory course and today I want to talk to you about conditionals! - Life is filled with making decisions, every moment you weigh the options at hand and make a decision based on what will be most useful for you at a given moment. If it is sunny outside you take your sunglasses, if it is raining outside you take an umbrella with you, if you are hungry you eat food etc. Well you’re not the only one that makes decisions, so can your computer! - How does your computer make decisions, and what goes on behind the scenes for your computer to make a decision? - Today we will talk about booleans which help your computer make decisions, and conditionals which will actually make them. - We talked about different data types in the past weeks like int, float, str (string) and input. - Bool is another Python data-type! - A bool can have two values: it can either be True or False. - These are called Boolean values, named after George Boole, who invented algebraic logic. - The first letter of each Boolean values must be capitalized when you are writing code. - To be able to get Boolean values you need to be able to compare other values. Booleans naturally arise when you compare values, for example, if you assert that a variable x is greater than 5, that comparison will be either True or False. - In order to compare values you need to use relational operators. - There are many relational operators and you should go over each one to make sure that you understand the purpose and meaning of each one. Some of the relational operators are "greater than," "less than or equals," and "not equals." - You can use relational operators to compare different types of values. For example, just like in math you can use it on floats or integers. - When you execute the line of code that states “Five is greater than six” your computer will give you the Boolean value of False as you would expect, just like a mathematical operation that you are used to. - But relational operators are not limited to numbers, you can also use them on strings! This can be done in Python because Python automatically assigns a value to each character in a string. - For example if you execute the line of code that states “bat is less than cat” your computer will give you the Boolean value of True. This is because b comes before c in the alphabet therefore b is assigned a lower number compared to c, and therefore is less than (just like when sorting a dictionary, only if the first letters of two strings are tied will the second letters factor into the comparison). - One thing to look out for when comparing string values in differences in upper and lower case letters. - In most programming languages uppercase letters come before lowercase letters, meaning lowercase letters have a higher value associated with them. So if you executed the line of code that states “uppercase C cat is less than lower case b bat” you would get the Boolean value of True since lower case b has a higher value (97) than the upper-case C (67). - Some other logical operators that you will be using are not, and, or. These logical operators work just like they sound in English. - The not operator evaluates to the opposite of the truth value. For example if you executed a line of code that states “not parenthesis three is greater than five close-parenthesis“ you would get True because three is not greater than five. - The and, or operations are kind of easy to mix up but the most important difference between them is that the "and" operation is used when you want to check that ALL of the statements you are making are true. When you are using the "or" operation you are checking if AT LEAST one of the statements you are making is True. - For example if you executed a line of code that stated “(Three is less than five AND bat is less than cat)” you would get the boolean value of True since both statements are true. And if you executed a line of code that stated “(Three is greater than five OR bat is less than cat)” you would still get True, even though one of those statements is false, as three is not greater than five. But that doesn't matter because the or operator checks to see if at least one of the statements made is True. - Something that really helped me distinguish between using "and" and "or" was making Truth Tables. - A truth table is when you take two expressions and evaluate what the resulting boolean value would be based on the different operators you are using and the different bools the expressions can have. Making your own truth table is a great exercise if you feel stuck trying to figure out the differences between "and" and "or." - Understanding the differences between them is really important because as you improve at coding you will start combining logical operators. Meaning you will execute lines of code that feature multiple logical operators. So you could be executing a line of code that has multiple and’s and or’s! - That’s why it’s really important to know how to keep track of the results. In those cases, you should always use parentheses to explicitly specify how the operators are grouped with their operands. - Now that you have the tools to evaluate boolean values by using logical operators, let’s get more into conditionals! - A conditional is a block of code that starts with the word "if," followed by a condition expression which will evaluate to a Boolean value. When you write if, your computer can’t just run the code like it normally does, it has to make a decision! - That’s why using conditionals is very powerful and now that you have all the tools to code a conditional let’s get into how you can actually code it. - The first thing your computer does when you execute an if statement is to gather all of the lines of code which are indented at the same level as the first line of code following the if line. - This is why indenting is very important, you want to tell your computer which lines of code to apply the if statement to, and you do this through indentation. - If you indented correctly the condition expression that you have written using relational operators will be simplified and you will get a boolean value of either True or False. - If the boolean value of your conditional expression is True, then the lines of code that you had written will be executed, but if it was False then that block of code will be skipped over. - As you can see, using conditionals is very powerful, because you are essentially telling your computer to only execute some code when you know a condition you want is satisfied. By using conditionals you can make your computer essentially make decisions! - Just to go over what we talked about: - There is a new type we learned about called Boolean. A boolean type has two possible values, either True or False. - These are called boolean values. - You can write a conditional by using the keyword "if" and use relational operators in your conditional statement, and essentially tell your computer which line of codes you want it to execute and which ones you want it to skip over. - The power of if statements is definitely undeniable! But you are not just limited to if statements because you can also have else and elif. - What do else and elif statements do? Let’s say you wrote a block of code (indenting multiple lines at the same level) after an if statement and then you wrote a new block of code (indented at the same level as the if block) putting an else before it, indented to match the if. - In this situation, if the first block of code with the if statement was skipped over because the condition of the if was False, then you are guaranteed to execute the else block of code (we call these branches). - Essentially using an else statement with an if statement guarantees that you always execute one branch or the other. Because if the if branch isn't executed the else branch always will be. And vice versa, if the if branch is executed the else branch will always be skipped over. - This means that the if and else branches are mutually exclusive. This quality is what ensures there is always some branch of code that is executed no matter whether the if condition evaluates to True or False! - Besides the else statement there is also an elif statement. - If/else allows you to create two mutually exclusive branches, but what if you need more? - For example, the outcome of a game might be a win, a loss, or a tie. In this case, we might want three different things to happen depending on these three possibilities, and we can add an elif branch between our if and else branches to achieve this. - If a block of code after an if statement block of code (indented at the same level) starts with elif, the condition on the if block is evaluated first, and if it's true, the elif will be skipped, along with the else. - But if the if condition is False, the elif condition will be evaluated, and if it's True, that block will be executed (and the else will be skipped). - If both the if and elif conditions are false, any further elif cases will be checked, and if their conditions are all False, a final else block will execute (if it's present). - Essentially the elif block of code allows you to check multiple expressions for True one-by-one, and execute a block of code as soon as one of the conditions evaluates to True. - Elif and else statements are not required when you are writing conditional statements, the only required statement is the if statement. But they can be very powerful tools, and you will mostly likely need to use them. - Another important note to add is that an elif statement can be used multiple times in your code following an if statement, to set up as many branches as you need, however there can only be one else statement following an if statement! - If this all seems hard to follow, don’t worry. When you are thinking about executing conditionals take each statement one step at a time and evaluate whether each statement will be a True or a False and based on that move on to the next statement. - A very helpful visual tool can be making flow charts. You can basically draw a diagram of what will happen when each line of code will be executed. - At a high level, Booleans are Python's way of representing True or False, and conditionals are set up using if, elif, and/or else to allow Python to use Booleans to make decisions about whether or not to execute certain blocks of code. - To create conditions for conditional statements, we usually use comparison operators or custom functions that return Booleans to specify the conditions that we want to use. - Put all of these things together, and your code can be a lot more flexible than what's possible just using function definitions alone. - This was Path to Programming hope! It was great talking to you, see you next time.
Unit 4: Loops and Lists
-
"Sequences and Loops" (10:11)
Talks about sequences, including indexing and slicing, and loops, including for and while loops.
Click here to download 05_sequences_and_loops.mp3
Click here to download 05_sequences_and_loops_script.txtShow the script
- Hello! Welcome to the Path to Programming; the audio supplementary materials for introduction to computer science! - I am a former student that took this introductory course and today I want to talk to you about Sequences and Loops! - Last week talked about conditionals and how our computer can make decisions for us based on a condition we gave to our computer. - This week we will talk about how your computer would behave if you wanted your computer to keep working until you gave it a condition to stop working. - A basic example we can consider is counting the number of vowels in a word. We already know how to write our own function, from the previous weeks, to determine if a letter is a vowel or not. - If we could apply this function to each letter in a word and count the results, then we could count vowels. But first, let's talk about sequences. - Strings, lists, and ranges are all sequences and we need to learn about the properties of sequences such as indexing in order to be able to understand how to use loops on sequences. - We can use a lot of built in functions on sequences to get information about them. - So far we talked about strings, but we haven’t really touched on what lists and ranges are. We will talk more about both of them in this episode. - You will also be learning more about lists in the future as their own data type. - But let's start with common properties of all sequences, using strings as an example... - To begin with, every sequence in python can be indexed: you can use an integer to pull out a single item. - Indices start at 0 and go to the length of the sequence minus one. - For example if you had the string “Path” and you accessed the third index you would get the letter h (as a single-letter string). P A T H zero one two three. - To index a sequence in Python, write the sequence (or the name of the variable you've stored it in) and then add square brackets afterwards, with the index integer inside the brackets. You could also use a complex expression or variable in the brackets. - In addition to indexing them, sequences can be sliced: use square brackets just like an index, but put a colon inside to separate two integers, and you can grab a sub-sequence between those two positions. - For example, if we sliced the word "path" from index zero to index two, we'd get the letters P and A (the slice goes up to but NOT including the end index). - A slice can even use two colons to provide three numbers, where the third number is a step value indicating how fast to go; a step of 2 would skip every other letter, for example. - Since indices are used so often for dealing with sequences, Python actually has a special kind of sequence called a "range" that can be used to easily generate indices for any other sequence. - The built-in "range" function can be called with 1, 2, or 3 parameters, to specify a start, stop and step, and it gives you back a special range-type sequence of integers that starts at the start value, ends just before (but not including) the stop value, and changes by the step value each time. - If you just call range with 1 parameter, it uses a start value of 0 and a step value of 1, so it will give you a range containing the integers from 0 up to but not including the number you gave it, and if that number is the length of another sequence, that range will contain exactly the indices of that sequence. - This is why range(len()) is a kind of idiom in Python: throw any sequence inside of len, and call range on the result, and you'll get a special sequence containing the indices of the first sequence, including the part where it starts at zero and stops before it reaches the length of the sequence. - For example, the word "hello" as a string is a sequence with 5 items, which are the individual letters, and it has indices zero, one, two, three, and four. - If we call len(hello), we'll get the number 5, and if we call range(5), we'll get a range with the numbers zero through four. - So if we call range(len("hello")), we'll get the right indices to use with that string. - But why would we want the indices of a sequence as another sequence, how is that even useful? - It turns out that one of Pythons loops, the for loop, operates exclusively on sequences. With a for loop, we can take a block of code and cause it to repeat once for each item in a sequence. - And what's even better is that with a for loop we get to declare a loop variable, which automatically gets assigned to the current item in the sequence. - We can use a for loop directly with a sequence, and our loop variable will hold items from that sequence, like letters if it's a string. Or, we could use range and len like we just talked about so that the for loop will iterate over the indices of our original sequence, which is called an index loop. - If we just want to repeat some code a set number of times and we don't care about a sequence, we could also use the range function, without len, to construct a sequence of numbers that has the length we want. - In all three cases: iterating over values, iterating over indices, or iterating over a custom range, the for loop works the same way. - You write for "loop variable" in sequence, put a colon, and then add an indented block of code. - You get to pick the name of the loop variable of course, so you might write "for letter in word" or "for number in range(5)". Python will then repeat the code in the block once for each item in the sequence, and during each repetition (called an "iteration") the loop variable will take on the value of a different item in the sequence. - So if we need to do something like count vowels in a word, we could use a for loop to do that, getting letters into the loop variable and checking them one by one. - There are actually two kinds of loops in Python. In addition to or loops, there are also while loops. - Last week when we talked about conditionals we talked about the if statement. You can think of a while loop as an if statement that constantly repeats itself until its condition becomes False. - When you execute a while loop you write the word while and then your condition, which is a boolean expression just like for an if statement. - The difference is that once the following block of code is complete, an if statement will continue to the code afterwards, but a while loop will check the condition again, and keep repeating its block of code until the condition evaluates to False. - So what exactly happens in your computer when you write a while loop? - First of all a line of code that starts with the keyword "while" is a while loop, so when you computer sees this keyword it starts executing the while loop. - Then your computer gathers all of the lines of code which are indented at the same level as the first line of code following the while line (including that first line of code). This is the loop body. - Your computer has to determine whether or not to run the loop body and the way that is determined is by checking the continuation condition. - If the continuation condition evaluates to True (because remember the continuation condition is a boolean expression), the loop body is executed using all of the normal rules for executing code, including these rules about loops. - If the continuation condition is not met, the loop body is skipped and execution continues after it. - If the loop body is not skipped, when the body is finished executing the while statement is revisited and the steps start again. - So the loop condition is simplified again, and if it still simplifies to a true boolean, the loop body is run again. - This process continues until the loop condition simplifies to a False value, at which point the loop body is skipped and the loop ends. - If the loop condition never becomes False, the loop will continue indefinitely, which is called an "infinite loop." - That’s why it’s easy to think about while loops as if statements that repeat themselves. - A concrete example would be counting down, like for a rocket launch. - First, we could set up a variable called n, with the value 10. - Then, we could use a while loop with the condition n is greater than or equal to zero, and in the loop we could write print(n). - With just that code, Python would keep printing 10 forever. - But if we add another line of code inside the loop that says n gets n minus one, then it will count down, starting at 10 and counting until it reaches zero. - After it prints zero, n will be assigned to -1, which will cause the condition to be False, and the loop will stop. - One last thing I want to touch on in this episode is the use of accumulation variables. - Often when we use loops, we want to build something up across different iterations, perhaps by adding numbers together into a sum, or by concatenating strings together into a longer message. - To do these kinds of things, we can create a variable before the loop begins, and then update that variable in the loop by adding to it. - Since each iteration of the loop will add to the same variable, by the end of the loop it will have accumulated a result. - For more complex results, you can use a conditional inside the loop as well, so that the counter is only updated on some iterations, not all the time. - This kind of setup is how you would solve the counting vowels problem we talked about at the beginning of this episode. - This week we talked about sequences, and for loops which are used to iterate through sequences. - We also talked about while loops, which use a continuation condition instead of a sequence to control their iteration. - Make sure you understand the properties of sequences, such as indices and how these properties are used when iterating using loops. - This was Path to Programming hope! It was great talking to you, see you next time.
-
"Lists and Memory Diagrams" (11:35)
Talks about lists and memory diagrams. (work in progress)
Click here to download 06_lists_and_memory_diagrams.mp3
Click here to download 06_lists_and_memory_diagrams_script.txtShow the script
- Hello! Welcome to the Path to Programming; the audio supplementary materials for introduction to computer science! - I am a former student that took this introductory course and today I want to talk to you about Lists and Memory Diagrams! - If you remember the very first episode we talked about the memory model, and how imperative it was when it came to understanding how programming works on a basic level. We talked about how the memory model helps you understand variable assignments and by extension how a program runs. - You can think of a Memory Diagram as an extension of this model, as they will better help you understand how lists work, and what goes on behind the scenes in your computer when you code a list. - Last episode we mentioned how a list is a data type but we didn’t get into the specifics of what a list is or how it works. We touched on the fact that a list is also a type of sequence, which has indices. - What separates a list from other types of sequences like strings is the fact that they are mutable. - You might be wondering what exactly this means, and no it doesn’t mean you can silence a list! - Instead it means that you can change the contents of a list even after creating it. - Once you write a string, it’s final, if you made a typo there’s no going back, you would have to write a new string with the correct spelling, you can’t go back and individually edit the characters. - But with lists you can manipulate them after creating them, you can change individual items or the length of a list that you have created, and you can do this without any new variable assignments. - Lists can store elements of different types (e.g., integers, booleans, strings). - They are usually homogeneous, meaning that all of the elements in a list are of the same type, but Python allows heterogeneous lists too. - A list with no elements is called an empty list. - You initialize a list by using brackets! - Like we have always done, you need to assign a list that you create to a variable so you can access it later on. - There are a lot of keywords for operations in lists you will need to learn so that you can use the data type of lists in the most efficient way possible. - An important keyword you should know is “in”, this operation allows you to check whether an element is in your list. - If you had created a list of numbers from 1 to 10 and you wanted to see if it contained the number 15, you would use “in” and get a Boolean value, and in this case it would be false since the list you created only goes up to 10. - Another important keyword that you will be frequently using is “append”. - Append is a method that allows you to add an element to a list that you have created. - It has a single parameter, in which you enter the element you want to add to the list. - Append is very useful and powerful to use in the body of a loop so elements are added to a list on each iteration of a loop you can even append a list you've created to another list! - Append is like a command that states “add this to the end of the list”- make sure you memorize this! - The most used list method is append, because it is used to create new lists and add elements to them. - Another very important keyword is “pop.” - Pop allows you to remove an item from a list that you have created. - You enter an index as the parameter and the element at that index is then returned to you and it is also removed from the list. - If you don’t give pop a parameter, Python will assume the element at the last index should be removed. - The final method you should know and memorize is “insert”. - Insert has two parameters, the first is the index and the second is the element that you want to insert before that index. - Because it is more specific compared to append (remember append just adds to the end of the list that’s why it is super useful when iterating) we don’t use it as often but nonetheless it is very useful. - Like we talked about last week, lists have indices as they are a type of sequence. - Therefore lists have the ability to do indexing and slicing. You can use the same operations we talked about last week, to for example get specific elements from a list using indexing, or getting only a subset of a list using slicing. - Now let's start talking about memory diagrams. - As we mentioned in the very first week, visual tools can be really helpful to use when you are trying to understand how a program works behind the scenes. - Memory diagrams are a visual tool as they represent lists and help us understand how each of the methods we described work on lists. - It wouldn't be much help to you if I just sat here and described what a memory diagram looks like, my tip would be for you to search it up and familiarize yourself with it. - Make sure that you draw a memory diagram the first few times you encounter a problem or code that uses lists. Every time you draw a memory diagram you will get one step closer to internalizing how lists and the operations work. - Memory diagrams will help you understand which elements are contained within each index. They will become increasingly useful as you start encountering lists that have lists within them and have to use multiple indices. - Please make sure to utilize this tool as much as you can, until it becomes second nature to you! As a former student it definitely helped me really understand how indices and specifically lists work and it made using lists very enjoyable to me! - An important thing the memory diagrams can help you realize is the difference between aliases and twins. So what exactly are aliases and twins? - An alias implies that you have assigned the same list to two different variables. So you could have a variable a and a variable b pointing to the same list. When you access the list using the name a and make a change, the list will also reflect that change when you access the list using variable b. - Basically when you have an alias when you make a change you make using one variable also appears as a change in another variable. In terms of a memory diagram it implies that the two arrows from the variable names are pointing to the same thing, so when you mutate either there’s only one operation going on behind the scenes. - To make things more clear let’s think of a real life example that reflects this situation. There is a special agent named Joe, for his work he uses the name Bond. When Joe goes to the tattoo store and gets a tattoo so does the alias Bond because they are actually the same person, even though they use different names when needed. - Another scenario that arises from naming variables is the twins/clones example. - You can think of this scenario as the opposite situation of aliases. Twins arise when you assign different lists to different variables but the lists are the same. When you mutate one list that is technically identical to the other, the other one doesn't change because they have different variables assigned to them. So even though the lists contain the exact same elements, because they were created separately and accessed using different variables, mutating one doesn't mutate the other. - Following the tattoo example we used if Joe had an identical twin named James (so they have the same DNA) if Joe got a tattoo it wouldn't mean that James got a tattoo. The fact that they’re identical to start with doesn't mean a change happens to both of them. - Memory diagrams help make this clear: in a twins situation, two separate variables point to two separate lists that have the same exact content, so you can see that if one were to change, the other wouldn't. - We mentioned that lists are special because they are mutable, you can alter a list even after creating it. As a counter-example we said that strings are immutable. - Another type of immutable objects is a tuple. What are tuples? Tuples are essentially like lists but they are immutable. - The name comes from "quadruple", "quintuple," etc.: those words end with 'tuple,' so the general form with an unspecified number of elements is called a "tuple." - Tuples are still a form of sequence that contain elements, which are separated by commas and contained in parentheses. So when initializing a list if you recall you would use square brackets, but when initializing a tuple you would use regular parentheses. Like lists the elements in a tuple are separated by commas. - You can use operations we’ve used on strings like indexing and slicing since those operations don’t change a sequence, they just access information. But you can’t use the new operations we learned in this episode like append and pop on tuples because tuples are immutable and you can’t change a tuple after you’ve created one. - One last thing I want to quickly touch on in this episode is nested loops. This is a complicated topic that we will hopefully expand up on but I wanted to tie it into this episode because just like we mentioned that there can be a list inside a list, there can also be a loop inside a loop! - These types of loops are usually the for loop type we talked about and they’re called nested loops. The loop that is inside the body of the for loop is called…. As you might have guessed, the inner loop. - The entire inner loop is executed each time the other loop is iterated, just like the rest of the commands in the outer loop body. - I would suggest that you experiment with loops yourself as they can be complicated to understand without trying them on your own! They are a very useful tool and can be used in combination with lists inside of lists. - The outer for example may be used to access a single list from a list of big lists and the inner loop may be used to iterate through the elements within the list accessed. Obviously hearing that is very mind boggling so I would urge you to try it on your own! - We've come to the end of another episode of path to Programming! - This week we talked about lists and memory diagrams and touched on nested loops as a concept. - Lists are very important and they are a type of sequence, what makes lists special is that they can be mutated, which means that they can be changed after they have been created. Some operations to change lists after creation that we touched on are append, pop and insert. - A way to understand how lists work and operate behind the scenes is to use memory diagrams. So as we said please make sure you use them to better understand lists and their operations! We gave an example to the complications that can be resolved by using memory diagrams with the alias and twin example. - And finally today we touched on the concept of for loops and how they can be useful. - I hope you enjoyed this week’s episode. Talk to you next time!
Unit 5: Dictionaries
-
"Dictionaries" (10:40)
Talks about dictionaries, including the difference between a collection and a sequence and accessing elements using keys.
Click here to download 07_dictionaries.mp3
Click here to download 07_dictionaries_script.txtShow the script
- Hello! Welcome to the Path to Programming; the audio supplementary materials for introduction to computer science! - I am a former student that took this introductory course and today I want to talk to you about Dictionaries! - Last week we talked about Lists which is a type of sequence and this week we will be talking about dictionaries which is a type of collection! - All sequences are collections but not all collections are sequences. - Dictionaries, like lists are used to store data but unlike lists you do not need an index to access the elements, instead you can access the elements using a key. - Crucially, lists are ordered. It matters that one element comes before another element. Indices specify the position of each element in the list. The elements in a dictionary are stored in key and value pairs. While Python does store these key-value pairs in a particular order, conceptually we consider dictionaries to be unordered. - You cannot use an index to access a dictionary. - Like with sequences, you can use the 'in' operator to check for an element. - With a dictionary though, the 'in' keyword checks if a key is in a dictionary. - Now that we have talked about the differences between collections and sequences let’s get into the nuts and bolts of dictionaries. - A Python dictionary is a mutable collection that maps keys to values. - This means that each value has a corresponding key which can be used to access those values. - Because a dictionary is mutable, we can add, change and remove key-value pairs. An important detail to note about the mutability of dictionaries is that only the values can be mutable (in case you don’t remember mutable means that you can change a value after creating it). - The keys are NOT mutable. Imagine if you had a key to get into your car. If the key was changeable, then the key might not work with the car anymore. This is why it is important that the keys are immutable. We do not want to lose access to our values. - To sum up, a dictionary consists of a collection of key-value pairs. Each key-value pair maps the key to its associated value. - To create a dictionary you will use curly brackets and you will use colons to separate the values from their keys. You will first name the key and then use the colon and then you write the value. - There are actually multiple ways to create a dictionary. - The first is to name your dictionary and each key-value pair. In this case you name your dictionary, and use curly brackets and then give your first key its name, then use a colon and then write the corresponding value. You can keep adding comma-separated key-value pairs. - Another way to initialize dictionaries is by using the dict keyword. Dict is a built-in function that allows you to enter a list of key and value pairs as tuples. - Finally you can create an empty dictionary and then add pairs using an assignment statement. - Simply write the name of the dictionary with the key in square brackets on the left hand side. Write the value on the right hand side. - I would suggest that you try all 3 ways to initialize a dictionary. Depending on the type of problem and how many value key pairs you will need to have you will prefer different methods. - My favorite method was definitely creating an empty dictionary and then using square brackets to name a key and give its associated values. - Another important thing to note is that a dictionary value can be of any type. This means that a value can be a string, a number, a list or even another dictionary! Any of the data types we covered are fair game to use in your dictionary as a value type. Same goes for keys. They just can't be mutable. - So if we can’t use indexing how can we access the values? A value can be retrieved from a dictionary by specifying its corresponding key in square brackets. - Because dictionaries are unordered, it does not matter in which order you input your data in a dictionary! You just need the key to access it. - If you refer to a key that is not in the dictionary, Python will give you an error. This type of error is specifically called a key error, since the key you are searching for does not exist. - One easy way to avoid this error from occurring is to use the in operator like you did in lists. - Also as we mentioned dictionaries are mutable. You can change the value associated with a key and you can also add or remove key-value pairs. But you cannot change the keys! - I know we are talking about a lot of concepts that apply to different parts of a dictionary, so an easy tool to help you are memory diagrams. As we mentioned in the previous weeks memory diagrams are helpful visual tools and if you are stuck on how the key value pair relationship works I would suggest drawing memory diagrams of dictionaries. I always mention how helpful memory diagrams were for me and this is just another instance of that. - So how can you add and delete pairs from a dictionary? Or how can you change the value to an existing key? - In order to add elements you can just use the assignment statement we mentioned where you write the name of the dictionary and use square brackets to name the key and then assign the value. - To delete an element you can use the pop method, which is the same method you use with lists. - If you want to overwrite the value for a key, you can use an assignment statement just like you did to add a new key-value pair. Simply use the same key and place the new value on the right-hand side. - Python also has a method called update that allows you to update it. You can use the update method by putting in the name of the dictionary and then putting dot update and using normal brackets. This method is useful to know but you will not be using it that much. - We have been talking about methods that mutate or change a dictionary after you have created it. I also want to mention some methods that do not mutate the dictionary but are very useful as they return elements in the dictionary. - If you want to get all the keys, use the dot keys method which returns all the keys in that dictionary. - Another method is dot values which returns all the values in the dictionary. - These methods are extremely useful and I would urge you to memorize them as you will be using them throughout. - Another useful method is the get method. The get method is another way to access the values in a dictionary but prevents raising a KeyError if the key does not exist. The get method is not too important for this class but can be handy. - Finally the dot items method returns the key value pairs as tuples. - The three methods keys, values and items are really powerful and you will be using the latter two when you are iterating. - The most limiting part of dictionaries can be the keys. - If you enter a key that does not exist you will get a key error, so as we mentioned before, always check if a key exists before you extensively use that key in your code. - Another limiting part of keys is that you can only have one key with a given name. Meaning that you can not have 2 different keys with the same name. Each key must have a unique name. Therefore duplicate keys are not allowed. This is because a dictionary maps each key to a corresponding value, so it doesn't make sense to map a particular key more than once. - Also, the keys of a dictionary must be of a type that is immutable, because as you recall keys are immutable. So you can’t have a key that is a list because they are mutable. This means a key has to be an immutable type like integer, float, string or boolean, most types we are used to using are immutable so this shouldn't be a problem when you’re coding but just a detail that I want you to keep in mind! - Up to now we have learned what a dictionary is, different ways to create a dictionary, how to use the key and value pair and why they are so powerful. - The last thing you will be doing with dictionaries is to iterate over them, generally with a for loop. You can iterate through keys separately or values separately or the key value pairs together. - When you are iterating through the keys in the dictionary you can iterate directly over the dictionary, you do not need to use the .keys method. An example snippet of code would be for key in my_dictionary. Again you don't need to use the .keys method. - However if you are iterating through values then you will need to use the .values method. An example of snippet code for this would look like for value in my_dictionary.values(). - The same is true when you are iterating through items (the key and value pairs), where you have to specify in your code that you are iterating through items by using the .items method. - Here we are at the end of another episode! - Today we talked about dictionaries, which is another very important data type in Python, alongside lists. - Lists and dictionaries are quite similar as they store a lot of data, but you access the data in them in very different ways. - Lists elements are accessed by indexing which is based on the order in which you enter the data, whereas dictionary elements are accessed by key that you associate with them, so they do not depend on the order in which you enter the data. - This is one of the greatest advantages of using a dictionary. But because of these differences in some instances it might be better to use a dictionary or a list and you should familiarize yourself with both so you know which one to choose. - We also talked about methods that are very important and useful for dictionaries such as pop, update, values, keys and items so make sure you also know all of these! Make sure you memorize their names and their purposes. - Also make sure that you are comfortable creating dictionaries with the 3 different methods we mentioned. - Thank you so much for listening this week! I hope you learned something new and I look forward to talking to you soon!