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.

Our lecture and problem set 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.

Reference Pages

Several other reference pages like this one provide additional material:

The Path to Programming

As an additional resource for the class beyond the textbook, we are producing audio recordings that cover course topics at a high level, week-by-week, 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.

Week 1: Getting Started

  1. "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.txt
    Show 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!
    
  2. "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.txt
    Show 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!
    
  3. "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.txt
    Show 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.
    

Week 2: Defining Functions

  1. "Functions" (12:23)
    Talks about functions, defining custom functions, and the function call model including function call frames, as well as the difference between print and return.


    Click here to download 03_functions.mp3
    Click here to download 03_functions_script.txt
    Show 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.
    

Week 3: Booleans and Conditionals

  1. "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.txt
    Show 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. 
    
    

Week 4: Loops and Lists

Work in progress.

Week 5: Dictionaries

Work in progress.

Week 6: Recursion

Work in progress.