alexmojaki / futurecoder

100% free and interactive Python course for beginners
https://futurecoder.io/
MIT License
1.31k stars 138 forks source link

test issue #5

Closed alexmojaki-bot closed 4 years ago

alexmojaki-bot commented 4 years ago

User Issue Email: admin@example.com User Agent: PC / Mac OS X 10.13.6 / Chrome 80.0.3987

heroku test

Redux state

```json { "rpc": { "loading": [], "error": null }, "book": { "server": { "hints": [ "

The code should be almost exactly the same, just make a couple of small changes.

", "

Make sure that the code inside if include: runs at the beginning of the loop, in the first iteration.

", "

That means include should be True at that point.

", "

Make sure that the code inside if include: doesn't run after the first iteration.

", "

That means include should be False after the first iteration.

" ], "page_index": 16, "showBirdseye": true, "showEditor": true, "showPythonTutor": false, "showSnoop": true, "step_index": 2 }, "pages": [ { "step_texts": [ "

At the bottom right of the screen is the shell. This is a place for running small bits of Python code. Just type in some code, press enter, and it'll run! Try it now:

\n
    \n
  1. Click anywhere on the shell (the black area).
  2. \n
  3. Type 1+2
  4. \n
  5. Press the Enter key on your keyboard.
  6. \n
", "

Great! Python evaluated 1+2 and got the result 3, so the shell displays that.

\n

The shell is probably your most important tool for learning Python, and you should spend lots of time experimenting and exploring in it. Be curious! Constantly ask yourself \"What would happen if I ran X?\" and then immediately answer that question by running it! Never be scared to try something out - if you get something wrong, nothing bad will happen.

\n

Try doing some more calculations now. You can multiply numbers with *, divide with /, and subtract with -. You can also use parentheses, i.e. ( and ).

", "

Excellent! Keep experimenting. When you're ready, click 'Next' to continue.

" ], "title": "Introducing The Shell" }, { "step_texts": [ "

Here's a tip: often you will want to re-run a previously entered bit of code, or a slightly modified version of it. You can copy and paste, but that's tedious and gets in the way of experimenting. A better method is to press the Up Arrow key on your keyboard. This will insert the previous line of code into the shell. Keep pressing it to go further back in your history, and if you go too far, press the Down Arrow key to go the other way. Try using it now.

" ], "title": "Navigating Shell History" }, { "step_texts": [ "

Python lets you do much more than calculate. In fact, we're not going to touch numbers or maths for a while. Instead, we're going to look at strings. Strings are essentially snippets of text. For example, enter the following into the shell, quotes (') included:

\n
'hello'\n
", "

The shell simply gives the same thing back because there's nothing to further to calculate. 'hello' is simply equal to 'hello'.

\n

A string is a sequence of characters. A character is a single symbol such as a letter, number, punctuation, space, etc. In this case the string contains the 5 characters hello. The quotes are not part of the string - they are there to tell both humans and computers that this is a string consisting of whatever characters are between the quotes.

" ], "title": "Introducing Strings" }, { "step_texts": [ "

Strings can be added together using +, although this means something very different from adding numbers. For example, try:

\n
'hello' + 'world'\n
", "

You can see that + combines or joins two strings together end to end. Technically, this is called concatenation.

\n

Here's an exercise: change the previous code slightly so that the result is the string 'hello world', i.e. with a space between the words.

\n

By the way, if you get stuck, you can click the lightbulb icon in the bottom right for a hint.

", "

Well done! Any of the following are valid solutions:

\n
'hello ' + 'world'\n'hello' + ' world'\n'hello' + ' ' + 'world'\n
" ], "title": "Adding Strings" }, { "step_texts": [ "

To make interesting programs, we can't always manipulate the same values. We need a way to refer to values that are unknown ahead of time and can change - values that can vary. These are called variables.

\n

Run this code:

\n
word = 'Hello'\n
", "

This creates a variable with the name word that refers to the string value 'Hello'.

\n

Check now that this is true by simply running word in the shell by itself.

", "

Good. For comparison, run 'word' in the shell by itself, with the quotes.

", "

As you can see, the quotes make all the difference. 'word' is literally just 'word', hence it's technically called a string literal. On the other hand, word is a variable, whose value may be anything.

\n

Similarly, 'sunshine' is 'sunshine', but what's sunshine without quotes?

", "

The answer is that sunshine looks like a variable, so Python tries to look up its value, but since we never defined a variable with that name we get an error.

" ], "title": "Introducing Variables" }, { "step_texts": [ "

Previously we made a variable called word with the value 'Hello' with this code:

\n
word = 'Hello'\n
\n

Now make a variable called name whose value is another string. The string can be anything...how about your name?

", "

You can use variables in calculations just like you would use literals. For example, try:

\n
'Hello ' + name\n
", "

Or you can just add variables together. Try:

\n
word + name\n
", "

Oops...that doesn't look nice. Can you modify the code above so that there's a space between the word and the name?

", "

Perfect!

\n

Variables can also change their values over time. Right now word has the value 'Hello'. You can change its value in the same way that you set it for the first time. Run this:

\n
word = 'Goodbye'\n
", "

Now observe the effect of this change by running word + ' ' + name again.

", "

Those quotes around strings are getting annoying. Try running this:

\n
print(word + ' ' + name)\n
", "

Hooray! No more quotes! We'll break down what's happening in this code later. For now just know that print(<something>) displays <something> in the shell. In particular it displays the actual content of strings that we usually care about, instead of a representation of strings that's suitable for code which has things like quotes. The word print here has nothing to do with putting ink on paper.

" ], "title": "Using Variables" }, { "step_texts": [ "

It's time to stop doing everything in the shell. In the top right you can see the editor. This is a place where you can write and run longer programs. The shell is great and you should keep using it to explore, but the editor is where real programs live.

\n

Copy the program below into the editor, then click the 'Run' button:

\n
word = 'Hello'\nname = 'World'\nprint(word + ' ' + name)\nword = 'Goodbye'\nprint(word + ' ' + name)\n
", "

Congratulations, you have run your first actual program!

\n

Take some time to understand this program. Python runs each line one at a time from top to bottom. You should try simulating this process in your head - think about what each line does. See how the value of word was changed and what effect this had. Note that when print is used multiple times, each thing (Hello World and Goodbye World in this case) is printed on its own line.

\n

Some things to note about programs in the editor:

\n
    \n
  1. The program runs in the shell, meaning that the variables defined in the program now exist in the shell with the last values they had in the program. This lets you explore in the shell after the program completes. For example, name now has the value 'World' in the shell.
  2. \n
  3. Programs run in isolation - they don't depend on any previously defined variables. The shell is reset and all previous variables are cleared. So even though word currently exists in the shell, if you delete the first line of the program and run it again, you'll get an error about word being undefined.
  4. \n
  5. If you enter code in the shell and it has a value, that value will automatically be displayed. That doesn't happen for programs in the editor - you have to print values. If you remove print() from the program, changing the two lines to just word + ' ' + name, nothing will be displayed.
  6. \n
\n

I recommend that you check all of these things for yourself.

" ], "title": "Writing Programs" }, { "step_texts": [ "

Often you will use variables to store the results of calculations. This will help to build more complex programs. For example, try this program:

\n
word = 'Hello'\nname = 'World'\nsentence = word + ' ' + name\nprint(sentence)\n
", "

Now sentence has the value 'Hello World' which can be used multiple times. Note that it will continue to have this value until it is directly reassigned, e.g. with another statement like sentence = <something>. For example, add these two lines to the end of the program:

\n
word = 'Goodbye'\nprint(sentence)\n
", "

Unlike a spreadsheet where formulas update automatically, a variable like sentence doesn't remember how it was calculated and won't change if the underlying values word or name are changed.

" ], "title": "Storing Calculations In Variables" }, { "step_texts": [ "

Good news! You've made it past the boring basics. We can start to write some interesting programs and have a bit of fun. One of the most powerful concepts in programming is the loop, which lets you repeat the same code over and over. Python has two kinds of loop: for loops and while loops. Here is an example of a for loop, try running this program:

\n
name = 'World'\nfor character in name: print(character)\n
", "

You can read the code almost like normal English:

\n
\n

For each character in the string name, print that character.

\n
\n

Each character is just a normal string. character is a normal variable that is given a new value before the code after the : runs. So the code above is equivalent to:

\n
name = 'World'\n\ncharacter = 'W'\nprint(character)\n\ncharacter = 'o'\nprint(character)\n\ncharacter = 'r'\nprint(character)\n\ncharacter = 'l'\nprint(character)\n\ncharacter = 'd'\nprint(character)\n
\n

Note that we could use a different variable name, character just makes it clearer.

\n

A for loop generally follows this structure:

\n
for <variable> in <collection>: <code to repeat>\n
\n

The for, in, and : are all essential.

" ], "title": "Introducing For Loops" }, { "step_texts": [ "

This example loop:

\n
for character in name: print(character)\n
\n

works, but actually it would usually (and should) be written like this:

\n
for character in name:\n    print(character)\n
\n

Specifically, the code to be repeated (known as the body) starts on a new line after the colon (:), and it must be indented, i.e. have some spaces before it. The code below without indentation is invalid, run it to see for yourself:

\n
for character in name:\nprint(character)\n
", "

The spaces are required to tell Python which lines of code belong to the body of the for loop. This is critical when the loop contains several lines, which it often will. For example, run this code:

\n
name = 'World'\n\nfor character in name:\n    print(character)\n    print('---')\n
", "

There are two indented lines, so they're both part of the body, so --- gets printed after each character. Now try running the same code without the indentation in the last line:

\n
name = 'World'\n\nfor character in name:\n    print(character)\nprint('---')\n
", "

Since print('---') is not indented, it's not part of the loop body. This means it only runs once, after the whole loop has finished running. Both programs are valid, they just do different things.

\n

The program below is invalid. Both lines in the loop body are indented, but by different amounts. The first line starts with 4 spaces, the second line starts with 2. Try running it.

\n
for character in name:\n    print(character)\n  print('---')\n
", "

When you indent, you should always indent by 4 spaces. Any consistent indentation is actually acceptable, but 4 spaces is the convention that almost everyone follows. Note that the editor generally makes this easy for you. For example, if you press the 'Tab' key on your keyboard in the editor, it will insert 4 spaces for you.

" ], "title": "Indentation" }, { "step_texts": [ "

Time for some exercises! Modify this program:

\n
name = 'World'\n\nfor character in name:\n    print(character)\n    print('---')\n
\n

to instead output:

\n
---W\n---o\n---r\n---l\n---d\n
", "

Splendid! Now write a program which prints name once for each character in name. For example, for name = 'Amy', it should output:

\n
Amy\nAmy\nAmy\n
\n

For name = 'World', it should output:

\n
World\nWorld\nWorld\nWorld\nWorld\n
\n

By the way, you can set name to anything in the first line. Only the rest of the program after that will be checked.

", "

We're making really good progress! You're solving problems and writing new code!\nLet's keep making things more interesting.

" ], "title": "Basic For Loop Exercises" }, { "step_texts": [ "

Before we look at some more loops, we need to quickly learn another concept. Look at this program:

\n
hello = 'Hello'\nprint(hello)\nhello = hello + '!'\nprint(hello)\n
\n

What do you think the line hello = hello + '!' does? What do you think the program will output? Make a prediction, then run it to find out.

", "

Python doesn't care that hello is on both the left and the right of the =, it just does what it would always do if the variables were different: it calculates hello + '!' which at the time is 'Hello' + '!' which is 'Hello!', and that becomes the new value of hello. If it helps, you can think of that line as split into two steps:

\n
temp = hello + '!'\nhello = temp\n
\n

or:

\n
temp = hello\nhello = temp + '!'\n
\n

This is very useful in a loop. Think about what this program will do, then run it:

\n
name = 'World'\nline = ''\nfor char in name:\n    line = line + char\n    print(line)\n
\n

By the way, '' is called the empty string - a string containing no characters.

", "

The details in the above program are important. What goes wrong if you swap the last two lines and run this program instead?

\n
name = 'World'\nline = ''\nfor char in name:\n    print(line)\n    line = line + char\n
", "

The last character in name only gets added to line at the end of the loop, after print(line) has already run for the last time. So that character and the full name never get printed at the bottom of the triangle.

" ], "title": "Building Up Strings" }, { "step_texts": [ "

Modify this program:

\n
name = 'World'\nline = ''\nfor char in name:\n    line = line + char\n    print(line)\n
\n

to add a space after every character in the triangle, so the output looks like this:

\n
W\nW o\nW o r\nW o r l\nW o r l d\n
", "

Tremendous! Now modify the program so that each line is backwards, like this:

\n
W\noW\nroW\nlroW\ndlroW\n
", "

Brilliant!

\n

Code like:

\n
line = line + char\n
\n

is so common that Python lets you abbreviate it. This means the same thing:

\n
line += char\n
\n

Note that there is no abbreviation for line = char + line.

\n

Now use += and a for loop to write your own program which prints name 'underlined', like this:

\n
World\n-----\n
\n

There should be one - for each character in name.

", "

Fantastic!

\n

By the way, when you don't need to use a variable, it's common convention to name that variable _ (underscore), e.g. for _ in name:. This doesn't change how the program runs, but it's helpful to readers.

\n

Let's make this fancier. Extend your program to draw a box around the name, like this:

\n
+-------+\n| World |\n+-------+\n
\n

Note that there is a space between the name and the pipes (|).

", "

You're getting good at this! Looks like you need more of a challenge...maybe instead of putting a name in a box, the name should be the box? Write a program that outputs this:

\n
+World+\nW     W\no     o\nr     r\nl     l\nd     d\n+World+\n
", "

Sweet! You're really getting the hang of this! If you want, here's one more optional bonus challenge. Try writing a program that outputs:

\n
W\n o\n  r\n   l\n    d\n
\n

Or don't, it's up to you.

" ], "title": "Building Up Strings Exercises" }, { "step_texts": [ "

Here's some words you need to know:

\n

An expression is a piece of code that has a value. For example, in this line of code:

\n
sentence = 'Hello ' + name\n
\n

there are three expressions:

\n
    \n
  1. 'Hello '
  2. \n
  3. name
  4. \n
  5. 'Hello ' + name
  6. \n
\n

By contrast, the full line sentence = ... is a statement. It's a command that tells the computer to perform an action. It has no value of its own. This means, for example, that you can't add statements together. This code is invalid:

\n
(word = 'Hello') + (name = 'Bob')\n
\n

Specifically, a statement like sentence = ... where a variable is given a value is called assignment - the value is assigned to the the variable.

\n

A program is a list of statements which are executed in order. A for loop is a compound statement, meaning it has a body of its own which contains other statements. Most statements will also contain expressions, and expressions can contain other smaller expressions, but expressions cannot contain statements.

\n

The process of calculating the value of an expression is called evaluation - note how it almost contains the word 'value'. The computer evaluates 1 + 2 to get the value 3.

\n

The process of executing a loop is called iteration. Code like for char in 'Hello': is iterating over the string 'Hello'. The fact that it's possible means that strings are iterable. By contrast, numbers are not iterable, which is exactly what Python will tell you if you try for char in 3:. Each run through the loop is one iteration, so in this example there will be 5 iterations.

" ], "title": "Basic Terminology" }, { "step_texts": [ "

Now we're going to learn how to tell the computer to make decisions and only run code\nunder certain conditions. For this we will need a new type of value. You've seen\nnumbers and strings, now meet booleans. There are only two boolean values:\nTrue and False. Try this program:

\n
condition = True\nprint(condition)\ncondition = False\nprint(condition)\n
", "

Booleans are meant to be used inside if statements (sometimes also called conditionals).

\n

Here is a simple example for you to run:

\n
if True:\n    print('This gets printed')\n\nif False:\n    print('This does not')\n
", "

Note how the code inside the first if statement ran, but not the second.

\n

In general, an if statement looks like this:

\n
if <condition>:\n    <body>\n
\n

where <condition> is any expression which evaluates to a boolean and <body> is an indented list\nof one or more statements. The structure is quite similar to a for loop. Note the colon (:) which\nis essential.

\n

When the computer sees if <condition>:, it checks if <condition> is True. If it is, it runs the body.\nIf not, it skips it and continues to the rest of the program.

\n

Here's a more interesting example for you to run:

\n
sentence = 'Hello World'\nexcited = True\nif excited:\n    sentence += '!'\nprint(sentence)\n
", "

(Remember that sentence += '!' means sentence = sentence + '!')

\n

Change excited = True to excited = False and run the program again to see what the difference is.

", "

Time for an exercise. Modify the program above to include an extra\nboolean parameter confused, so the program should start like this:

\n
sentence = 'Hello World'\nexcited = False\nconfused = True\n
\n

(sentence can be any string and the two booleans can be either True or False)

\n

When confused is true, the printed sentence should have a question mark added to the end.\nIf both confused and excited are true, the sentence should end with !?.

", "

Well done! This program can do 4 different things depending on how you combine excited\nand confused. Try them out if you want.

" ], "title": "Introducing If Statements" }, { "step_texts": [ "

Compound statements like for loops and if statements have bodies which are a list\nof inner statements. Those inner statements can be anything, including other compound statements.\nTry this example of a for loop inside an if statement for when you want to show\nthat you're really excited:

\n
sentence = 'Hello World'\nexcited = True\n\nif excited:\n    new_sentence = ''\n    for char in sentence:\n        new_sentence += char\n        new_sentence += '!'\n    sentence = new_sentence\n\nprint(sentence)\n
", "

Note how the body of the if statement (5 lines) is indented as usual, while the body\nof the for loop (2 lines) is indented by an additional 4 spaces in each line to show that\nthose lines are within the for loop. You can see the overall structure of the program\njust by looking at the indentation.

\n

Alternatively, you can put an if inside a for:

\n
sentence = 'Hello World'\nexcited = True\n\nnew_sentence = ''\nfor char in sentence:\n    new_sentence += char\n    if excited:\n        new_sentence += '!'\n\nsentence = new_sentence\nprint(sentence)\n
\n

These two programs have the exact same result. However the first one is more efficient as it\nonly iterates over the string if it needs to, since when excited = False nothing changes.

" ], "title": "Combining Compound Statements" }, { "step_texts": [ "

Run this program:

\n
sentence = 'Hello World'\n\ninclude = False\nnew_sentence = ''\nfor char in sentence:\n    if include:\n        new_sentence += char\n    include = True\n\nprint(new_sentence)\n
", "

As you can see, it prints everything but the first character. Take some time to understand how this works.

\n

In fact, it's time to introduce a new tool to help you understand programs. Click the 'Snoop' button to run the same program while also showing what's happening.

", "

Tada! Scroll to the top of the terminal and let's walk through what snoop is showing you.\nIt starts out very straightforward:

\n
    1 | sentence = 'Hello World'\n    3 | include = False\n    4 | new_sentence = ''\n    5 | for char in sentence:\n ...... char = 'H'\n
\n

The first lines are simply showing you the lines of the program that the computer ran.\nOn the left is the line number as seen in the editor.

\n

Running for char in sentence: assigns a value to the variable char, so snoop shows you that value.\nLines starting with ...... indicate a new variable or a change in the value of an existing variable.\nSuch lines will not be shown when they're redundant, which is why the snoop output doesn't start like this:

\n
    1 | sentence = 'Hello World'\n ...... sentence = 'Hello World'\n    3 | include = False\n ...... include = False\n    4 | new_sentence = ''\n ...... new_sentence = ''\n    5 | for char in sentence:\n ...... char = 'H'\n
\n

The next two lines are:

\n
    6 |     if include:\n    8 |     include = True\n
\n

What's important here is what's not showing: because include is False, line 7 (new_sentence += char) gets skipped. But then include is set to True, so the next iteration of the loop is different:

\n
    5 | for char in sentence:\n ...... char = 'e'\n    6 |     if include:\n    7 |         new_sentence += char\n .............. new_sentence = 'e'\n
\n

new_sentence += char runs for the first time and the variable new_sentence gets a new value.

\n

Now modify the program to do the opposite: only print the first character, leave out the rest.

", "

Great job! You're working with increasingly complex programs.

" ], "title": "Understanding Programs With Snoop" }, { "step_texts": [ "

An if statement can optionally have an else part. Run this example:

\n
condition = True\nif condition:\n    print('Yes')\nelse:\n    print('No')\n
", "

Now change the first line to condition = False and run it again.

", "

Think of else as saying 'or else' or 'otherwise'. It means that if the condition in the if\nis false, then the body of the else will run instead. Whether the condition is true or false,\nexactly one of the two bodies will run.

\n

Here's a more interesting example to run:

\n
sentence = 'Hello World'\nexcited = True\nif excited:\n    sentence = sentence.upper()\nelse:\n    sentence = sentence.lower()\nprint(sentence)\n
", "

sentence.upper() is a new kind of expression we haven't encountered yet. What's going on here is that sentence is a string and strings have various methods that let you conveniently calculate new values from them, including upper and lower. The names refer to uppercase (capital letters) and lowercase (small letters). 'Hello World'.upper() evaluates to 'HELLO WORLD'. It doesn't change the contents of sentence though, so you have to assign the new value again with sentence = sentence.upper().

\n

Now change excited to False and run it again.

", "

Here's a broken program:

\n
sentence = 'Hello World'\nexcited = True\n\nif excited:\n    char = '!'\nsentence += char\n\nprint(sentence)\n
\n

Can you see the problem? If you run it, everything seems fine. What could go wrong?

\n

Spoilers below! Have you figured it out?

\n

What happens if you change excited to False?

", "

If excited is true then char is defined and everything runs fine. But otherwise\nchar never gets assigned a value, so trying to use it in sentence += char fails.

\n

Fix this by adding an else clause to the if so that if excited is false, a full stop (.)\nis added to the end of the sentence instead of an exclamation mark (!).

", "

Time for a challenge!

\n

Write a program which, given a string sentence, prints a modified version with\nthe same letters, where the first letter is capitalised and the rest are lowercase.\nFor example, the output should be Hello world whether the input sentence = 'hello world'\nor 'HELLO WORLD'.

", "

Excellent!!!

\n

One more exercise, and then you can relax.

\n

Write a program which prints sentence mockingly, e.g:

\n
OnE MoRe eXeRcIsE, aNd tHeN YoU CaN ReLaX.\n
\n

Every second character should be lowercased, the rest should be uppercase.

", "

Perfect! Take a moment to be proud of what you've achieved. Can you feel your brain growing?

" ], "title": "if and else" }, { "step_texts": [ "

There are several ways to obtain booleans without assigning them directly,\nwhich allows you to construct very useful if statements. In particular there\nare many comparison operators which compare the values of two expressions.\nThe most common is the equality operator which checks if two values are equal.\nIt's denoted by two equals signs: ==. Try running this:

\n
print(1 + 2 == 3)\nprint(4 + 5 == 6)\nprint('ab' + 'c' == 'a' + 'bc')\n
", "

As you can see, if the values are equal, the equality expression evaluates to True,\notherwise it's False.

\n

Note the difference between the equality operator == and a single = which has different meanings,\nparticularly in assignment statements as you've seen them so far. What happens if you try\nremoving a single = from the previous program?

", "

Let's use == in an if statement. In this program, the if body runs only when c is the character 's'. See for yourself.

\n
name = 'kesha'\nnew_name = ''\nfor c in name:\n    if c == 's':\n        c = '$'\n    new_name += c\n\nprint(new_name)\n
", "

Now extend the program to also replace e with 3 and a with @.

", "

Well done!

" ], "title": "The Equality Operator" }, { "step_texts": [ "

Quick biology lesson! Most of the cells in your body contain your full genetic code in DNA.\nThis consists of strands of molecular units called nucleobases which come in four varieties:\nAdenine, Cytosine, Guanine, and Thymine, or ACGT for short.\nSo part of a single strand might be something like:

\n
AGTAGCGTCCTTAGTTACAGGATGGCTTAT...\n
\n

This will be paired with another strand where A is replaced by T and vice versa,\nand C is replaced by G and vice versa, e.g:

\n
TCATCGCAGGAATCAATGTCCTACCGAATA...\n
\n

The two strands are 'zipped' together into the famous double helix structure,\njoined by the matching A-T and C-G pairs. These pairings are essential in copying DNA when\ncells divide and reproduce. The double helix is unzipped and the code is transcribed\ninto its opposite version to make the copy.

\n

We're going to repeat that process. Let's try the same kind of program we just wrote:

\n
dna = 'AGTAGCGTC'\nopposite_dna = ''\nfor char in dna:\n    if char == 'A':\n        char = 'T'\n    if char == 'T':\n        char = 'A'\n    if char == 'G':\n        char = 'C'\n    if char == 'C':\n        char = 'G'\n    opposite_dna += char\n\nprint(opposite_dna)\n
", "

Oh dear, that doesn't quite work. T is changed to A but A isn't changed to anything.\nCan you see why?

\n

When char == 'A', then the body char = 'T' does indeed run. But that means that the following\ncondition char == 'T' also passes and so char = 'A' and we're back where we started.\nWe need to only change char from T to A if char wasn't already A to begin with,\nmeaning char == 'A' was False. We can do that with an else, like so:

\n
if char == 'A':\n    char = 'T'\nelse:\n    if char == 'T':\n        char = 'A'\n
\n

Now fix the program to replace all characters correctly.

", "

Brilliant! You have mimicked what your own cells are constantly doing.

\n

An if inside an else can be replaced by a single keyword elif. For example,\nthe previous code can be changed to this:

\n
if char == 'A':\n    char = 'T'\nelif char == 'T':\n    char = 'A'\nelif char == 'G':\n    char = 'C'\nelif char == 'C':\n    char = 'G'\n
", "

It's common to have a chain of elif clauses when you want exactly one of many\nbodies to run, like in this case. In general, code like this:

\n
if X:\n    ...\nelse:\n    if Y:\n        ...\n    else:\n        if Z:\n            ...\n        else:\n            ...\n
\n

can be rewritten as:

\n
if X:\n    ...\nelif Y:\n    ...\nelif Z:\n    ...\nelse:\n    ...\n
\n

which is both shorter and saves you from unpleasant nested indentation.\nThe difference is only cosmetic: once the computer runs this code, it can't\ntell the difference between the two versions.

\n

Note that elif(s) can optionally be followed by one final else. We didn't include one\nin our DNA example, but we could add one to alert us to any unexpected characters\nin the input, or change elif char == 'C': to else: if we were confident\nabout the input being valid.

" ], "title": "Introducing elif" }, { "step_texts": [ "

The opposite of the equals operator == is the not equals operator !=. If you squint it sort of looks like \u2260. It evaluates to True when two values are...not equal. Try it for yourself in the shell.

", "

Here's a cute little program using !=:

\n
sentence = \"The e key on my keyboard is broken\"\nnew_sentence = ''\nfor c in sentence:\n    if c != 'e':\n        new_sentence += c\nprint(new_sentence)\n
", "

Other handy operators are < (less than) and > (greater than). For example, a < b means \"a is less than b\". Try using one of these in the shell to compare two numbers.

", "

You can also use these operators to compare strings. If you arrange two strings in alphabetical order, the first one is 'less than' the second. See for yourself.

", "

Here's a practical example of < in action for you to try:

\n
percentage = 73\n\nif percentage < 20:\n    grade = \"F\"\nelif percentage < 40:\n    grade = \"D\"\nelif percentage < 60:\n    grade = \"C\"\nelif percentage < 80:\n    grade = \"B\"\nelse:\n    grade = \"A\"\n\nprint(grade)\n
\n

Recall that elif percentage < 40 after if percentage < 20 means \"if the percentage wasn't less than 20 and also is less than 40\", so it will pass for all numbers from 20 to 39 inclusive. Similarly a 'C' is for percentages from 40 to 59, and an 'A' is for any number 80 and up.

", "

Now for an exercise: write a program that takes three variables x1, x2, and x3, and prints the value of the smallest one. So for:

\n
x1 = 'Charlie'\nx2 = 'Alice'\nx3 = 'Bob'\n
\n

it should print Alice.

", "

Marvelous!

\n

There are many ways this could be solved. Here's one solution:

\n
if x1 < x2:\n    if x1 < x3:\n        first = x1\n    else:\n        first = x3\nelse:\n    if x2 < x3:\n        first = x2\n    else:\n        first = x3\n\nprint(first)\n
\n

Here's another:

\n
first = x1\n\nif x2 < first:\n    first = x2\n\nif x3 < first:\n    first = x3\n\nprint(first)\n
\n

These programs (and yours too) all work equally well with numbers and strings,\nbut not a mixture.

\n

< and > evaluate to False if the compared values are equal. For example,\n3 is not less than 3, so 3 < 3 and 3 > 3 are both False.\nTo allow equal values, use <= and >=.\nAgain, if you squint, they look a bit like \u2264 and \u2265.\nNote that the = comes second - there are no such operators as =< or =>.\nTo remember this, read them out loud as \"less than or equal to\"\nand \"greater than or equal to\".

\n

In summary, the main comparison operators are ==, !=, <, >, <=, and >=.\nIf you ever have doubts about what they do, play with them in the shell!

" ], "title": "Other Comparison Operators" }, { "step_texts": [ "

It's time to learn about a powerful new type of value called lists. Here's an example:

\n
words = ['This', 'is', 'a', 'list']\n\nfor word in words:\n    print(word)\n
", "

A list is a sequence (an ordered collection/container) of any number of values.\nThe values are often referred to as elements.\nThey can be anything: numbers, strings, booleans, even lists! They can also be a mixture of types.

\n

To create a list directly, like above:

\n
    \n
  1. Write some square brackets: []
  2. \n
  3. If you don't want an empty list, write some expressions inside to be the elements.
  4. \n
  5. Put commas (,) between elements to separate them.
  6. \n
\n

Here's another example of making a list:

\n
x = 1\nthings = ['Hello', x, x + 3]\nprint(things)\n
", "

As you saw above, lists are iterable, meaning you can iterate over them with a for loop.\nHere's a program that adds up all the numbers in a list:

\n
numbers = [3, 1, 4, 1, 5, 9]\n\ntotal = 0\nfor number in numbers:\n    total += number\n\nprint(total)\n
", "

Now modify the program so that it can add up a list of strings instead of numbers.\nFor example, given:

\n
words = ['This', 'is', 'a', 'list']\n
\n

it should print:

\n
Thisisalist\n
", "

Optional bonus challenge: extend the program to insert a separator string between each word.\nFor example, given

\n
words = ['This', 'is', 'a', 'list']\nseparator = ' - '\n
\n

it would output:

\n
This - is - a - list\n
\n

Lists and strings have a lot in common.\nFor example, you can add two lists to combine them together into a new list.\nYou can also create an empty list that has no elements.\nCheck for yourself:

\n
numbers = [1, 2] + [3, 4]\nprint(numbers)\nnew_numbers = []\nnew_numbers += numbers\nnew_numbers += [5]\nprint(new_numbers)\n
\n

With that knowledge, write a program which takes a list of numbers\nand prints a list where each number has been doubled. For example, given:

\n
numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5]\n
\n

it would print:

\n
[6, 2, 8, 2, 10, 18, 4, 12, 10]\n
", "

Great!

\n

When you want to add a single element to the end of a list, instead of:

\n
some_list += [element]\n
\n

it's actually more common to write:

\n
some_list.append(element)\n
\n

There isn't really a big difference between these, but .append\nwill be more familiar and readable to most people.

\n

Now use .append to write a program which prints a list containing only the numbers bigger than 5.

\n

For example, given:

\n
numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5]\n
\n

it would print:

\n
[9, 6]\n
", "

Fantastic! We're making great progress.

" ], "title": "Introducing Lists" }, { "step_texts": [ "

Exercise: write a program which takes a list and a value and checks\nif the list contains the value. For example, given:

\n
things = ['This', 'is', 'a', 'list']\nthing_to_find = 'is'\n
\n

it should print True, but for

\n
thing_to_find = 'other'\n
\n

it should print False.

", "

Nice!

\n

A typical solution looks something like this:

\n
found = False\nfor thing in things:\n    if thing == thing_to_find:\n        found = True\n\nprint(found)\n
\n

Your solution is probably similar. It's fine, but it's a bit inefficient.\nThat's because it'll loop over the entire list even if it finds the element at the beginning.\nYou can stop any loop using a break statement, like so:

\n
for thing in things:\n    if thing == thing_to_find:\n        found = True\n        break\n
\n

This is just as correct but skips unnecessary iterations and checks once it finds the element.\nYou can use snoop to see the difference.

" ], "title": "Using break to end a loop early" }, { "step_texts": [ "

Looping is great, but often you just want to retrieve a single element from the list at a known position.\nHere's how:

\n
words = ['This', 'is', 'a', 'list']\n\nprint(words[0])\nprint(words[1])\nprint(words[2])\nprint(words[3])\n
", "

In general, you can get the element at the position i with words[i]. The operation is called subscripting or indexing, and the position is called the index.

\n

You've probably noticed that the first index is 0, not 1. In programming, counting starts at 0. It seems weird, but that's how most programming languages do it, and it's generally agreed to be better.

\n

This also means that the last index in this list of 4 elements is 3. What happens if you try getting an index greater than that?

", "

There you go. words[4] and beyond don't exist, so trying that will give you an error.

\n

By the way, you can get the number of elements in a list (commonly called the length) using len(words).\nThat means that the last valid index of the list is len(words) - 1, so the last element is words[len(words) - 1]. Try these for yourself.

\n

So in general, the valid indices are:

\n
[0, 1, 2, ..., len(words) - 2, len(words) - 1]\n
\n

There's a handy built in function to give you these values, called range:

\n
for i in range(10):\n    print(i)\n
", "

range(n) is similar to the list [0, 1, 2, ..., n - 2, n - 1].\nThis gives us an alternative way to loop over a list:

\n
words = ['This', 'is', 'a', 'list']\n\nfor index in range(len(words)):\n    print(index)\n    print(words[index])\n
", "

Let's get some exercise! Given a list things and a value to_find,\nprint the first index of to_find in the list, i.e. the lowest number i such that\nthings[i] is to_find. For example, for

\n
things = ['on', 'the', 'way', 'to', 'the', 'store']\nto_find = 'the'\n
\n

your program should print 1.

\n

You can assume that to_find appears at least once.

", "

Nice!

\n

By the way, indexing and len() also work on strings. Try them out in the shell.

\n

Here's another exercise. Given two strings of equal length, e.g:

\n
string1 = \"Hello\"\nstring2 = \"World\"\n
\n

print them vertically side by side, with a space between each character:

\n
H W\ne o\nl r\nl l\no d\n
", "

Incredible!

\n

Your solution probably looks something like this:

\n
for i in range(len(string1)):\n    char1 = string1[i]\n    char2 = string2[i]\n    print(char1 + ' ' + char2)\n
\n

This doesn't work so well if the strings have different lengths.\nIn fact, it goes wrong in different ways depending on whether string1 or string2 is longer.\nYour next challenge is to fix this problem by filling in 'missing' characters with spaces.

\n

For example, for:

\n
string1 = \"Goodbye\"\nstring2 = \"World\"\n
\n

output:

\n
G W\no o\no r\nd l\nb d\ny  \ne\n
\n

and for:

\n
string1 = \"Hello\"\nstring2 = \"Elizabeth\"\n
\n

output:

\n
H E\ne l\nl i\nl z\no a\n  b\n  e\n  t\n  h\n
", "

Magnificent! Take a break, you've earned it!

" ], "title": "Getting Elements at a Position" }, { "step_texts": [ "

It's time to expand your vocabulary some more.

\n

print and len are functions. See for yourself:

\n
print(len)\nprint(print)\n
", "

An expression like len(things) or print(things) is a function call - when you write that, you are calling the function len or print. The fact that this is possible means that functions are callable:

\n
print(callable(len))\n
", "

Most things are not callable, so trying to call them will give you an error:

\n
f = 'a string'\nprint(callable(f))\nf()\n
", "

In the call len(things), things is an argument. Sometimes you will also see the word parameter, which means basically the same thing as argument. It's a bit like you're giving the argument to the function - specifically we say that the argument things is passed to len, and len accepts or receives the argument.

\n

len(things) will evaluate to a number such as 3, in which case we say that len returned 3.

\n

All calls have to return something...even if it's nothing. For example, print's job is to display something on screen, not to return a useful value. So it returns something useless instead:

\n
things = [1, 2, 3]\nlength = len(things)\nprinted = print(length)\nprint(printed)\n
", "

None is a special 'null' value which can't do anything interesting. It's a common placeholder that represents the lack of a real useful value. Functions that don't want to return anything return None by default. If you see an error message about None or NoneType, it often means you assigned the wrong thing to a variable:

\n
things = print([1, 2, 3])\nlength = len(things)\n
", "

A method is a function which belongs to a type, and can be called on all values of that type using .. For example, upper and lower are methods of strings, which are called with e.g. word.upper():

\n
word = 'Hello'\nprint(word.upper)\nprint(word.upper())\n
", "

Another example is that append is a method of lists. But you can't use .upper on a list or .append on a string:

\n
word = 'Hello'\nword.append('!')\n
", "

The word 'attribute' in the error message refers to the use of . - the error actually comes just from word.append, without even a call.

" ], "title": "Terminology: Calling functions and methods" }, { "step_texts": [ "

Let's review how to work with lists. Suppose we have a list nums = [1, 2, 3]. You can use:

\n
    \n
  • append: Add an element to the end of the list. nums.append(4) changes the list to [1, 2, 3, 4].
  • \n
  • len: Returns the number of elements. len(nums) is 3.
  • \n
  • range: range(n) is an object similar to the list of numbers from 0 to n - 1. In particular, range(len(nums)) is like [0, 1, 2].
  • \n
  • subscripting: Get a value at an index. nums[0] is 1, nums[1] is 2, nums[2] is 3.
  • \n
  • +: Concatenates lists. nums + [4, 5] is [1, 2, 3, 4, 5].
  • \n
\n

Here's some new things. Try them out in the shell.

\n
    \n
  • subscript assignment: Set a value at an index. nums[0] = 9 changes the list to [9, 2, 3].
  • \n
  • join: Add a list of strings with a separator in between. This is a method of strings (the separator) which takes an iterable of strings as an argument. '--'.join(['apples', 'oranges', 'bananas']) returns 'apples--oranges--bananas'. You can also use an empty string if you don't want a separator, e.g. ''.join(['apples', 'oranges', 'bananas']) returns 'applesorangesbananas'.
  • \n
  • sum: Add a list of numbers. sum(nums) is 6.
  • \n
  • in: A comparison operator that checks if a value is in a list. 2 in nums is True, but 4 in nums is False.
  • \n
  • index: Returns the first index of a value in a list. [7, 8, 9, 8].index(8) is 1. Raises an error if the value isn't there.
  • \n
\n

You may recognise some of these from your exercises. I assure you that those exercises were not pointless, as you've now learned valuable fundamental skills. For example, you can use in to check if a list contains 5, but there's no similarly easy way to check for a number bigger than 5.

\n

It's useful to know these functions, but it's not easy to learn them all, and there's many more. A more important skill is being able to look things up. For example, here are some typical ways you might Google the above functions if you forgot their names:

\n
    \n
  • append
      \n
    • python add element to list
    • \n
    • python add item at end of list
    • \n
    \n
  • \n
  • len
      \n
    • python size of list
    • \n
    • python number of elements in list
    • \n
    • python how many characters in string
    • \n
    \n
  • \n
  • join
      \n
    • python combine list of strings with separator
    • \n
    • python add together list of strings with string in between
    • \n
    \n
  • \n
  • sum
      \n
    • python add list of numbers
    • \n
    • python total of numbers
    • \n
    \n
  • \n
  • in
      \n
    • python check if list contains value
    • \n
    • python test if list has element
    • \n
    \n
  • \n
  • index
      \n
    • python get position of element
    • \n
    • python get index of value
    • \n
    \n
  • \n
\n

Let's practice this skill now. Find a function/method that returns the value in a list which is bigger than any other value. For example, given the list [21, 55, 4, 91, 62, 49], it will return 91. You should write the answer in the shell as a single small expression. For example, if you were looking for the function sum, you could write sum([21, 55, 4, 91, 62, 49]). Don't solve this manually with a loop.

", "

Good find! Let's do one more. If you have a list:

\n
nums = [1, 2, 3, 4, 5]\n
\n

You could write nums.append(9) and nums would change to:

\n
[1, 2, 3, 4, 5, 9]\n
\n

But suppose you don't want the 9 to be at the end, you want it to go between the second and third elements:

\n
[1, 2, 9, 3, 4, 5]\n
\n

Call the right function/method in the shell to do that.

", "

Perfect!

\n

It can also be useful to Google things like \"python list tutorial\", e.g. if:

\n
    \n
  • Googling a specific method has failed so you want to find it manually.
  • \n
  • You're still confused about lists after this course.
  • \n
  • It's been a while since you learned about lists and you need a reminder.
  • \n
  • You're struggling to solve a problem with lists and you need to go back to basics and strengthen your foundations.
  • \n
\n

There are also ways to find information without any googling. Try dir([]) in the shell.

", "

dir() returns a list of the argument's attributes, which are mostly methods. Many will start with __ which you can ignore for now - scroll to the end of the list and you'll see some familiar methods.

\n

Here are a few more useful functions/methods. Suppose nums = [28, 99, 10, 81, 59, 64]

\n
    \n
  • sorted: Takes an iterable and returns a list of the elements in order. sorted(nums) returns [10, 28, 59, 64, 81, 99].
  • \n
  • pop: Removes and returns an element at a given index. nums.pop(3) removes nums[3] (81) from the list and returns it. Without an argument, i.e. just nums.pop(), it will remove and return the last element.
  • \n
  • remove: Removes the first occurrence of the given element. nums.remove(10) will leave nums as [28, 99, 81, 59, 64]. Raises an error if the value doesn't exist. Equivalent to nums.pop(nums.index(10)).
  • \n
  • count: Returns the number of times the argument appears in the list. [1, 2, 3, 2, 7, 2, 5].count(2) is 3.
  • \n
\n

You've already seen that len and subscripting work with strings, a bit as if strings are lists of characters. Strings also support some of the new methods we've learned, not just for characters but for any substring. For example:

\n
    \n
  • 'the' in 'feed the dog and the cat' is True
  • \n
  • 'feed the dog and the cat'.count('the') is 2
  • \n
  • 'feed the dog and the cat'.index('the') is 5
  • \n
\n

Note that in most cases, methods which modify a list in place (append, insert, remove) merely return None, while the remaining functions/methods return a new useful value without changing the original argument. The only exception is the pop method.

\n

Modifying a value directly is called mutation - types of values which can be mutated are mutable, while those that can't are immutable. Strings are immutable - they don't have any methods like append or even subscript assignment. You simply can't change a string - you can only create new strings and use those instead. That means that this is a useless statement on its own:

\n
word.upper()\n
\n

The string referred to by word isn't modified, instead word.upper() returned a new string which was immediately discarded. If you want to change the value that word refers to, you have to assign a new value to the variable:

\n
word = word.upper()\n
\n

Or you can use word.upper() immediately in a larger expression, e.g.

\n
if word.lower() == 'yes':\n
" ], "title": "Functions And Methods For Lists" }, { "step_texts": [ "

It's time to learn about another tool to explore programs. Put some code in the editor and then click the new \"Python Tutor\" button. Here's some example code if you want:

\n
all_numbers = [2, 4, 8, 1, 9, 7]\n\nsmall_numbers = []\nbig_numbers = []\n\nfor number in all_numbers:\n    if number <= 5:\n        small_numbers.append(number)\n    else:\n        big_numbers.append(number)\n\nprint(small_numbers)\nprint(big_numbers)\n
\n

The button will open a new tab with a visualisation from pythontutor.com.\nThere you can navigate through the program step by step with the \"Prev\" or \"Next\" buttons, or drag\nthe slider left or right. You can also see the values of variables on the right.

" ], "title": "Understanding Programs With Python Tutor" }, { "step_texts": [ "

It's time to learn some technical details that are often misunderstood and lead to errors.\nRun this program:

\n
list1 = [1, 2, 3]\nlist2 = [1, 2, 3]\n\nprint(list1)\nprint(list2)\nprint(list1 == list2)\n\nprint(list1 is list2)\n\nlist1.append(4)\n\nprint(list1)\nprint(list2)\n
", "

This program is quite straightforward and mostly consists of things you're familiar with.\nWe create two variables which refer to lists.\nThe lists have the same elements, so they are equal: list1 == list2 is True.

\n

But then there's a new comparison operator: is. Here list1 is list2 is False.\nThat means that regardless of the two lists being equal,\nthey are still two separate, distinct, individual lists.\nAs a result, when you append 4 to list1, only list1 changes.

\n

Now change list2 = [1, 2, 3] to list2 = list1 and see what difference it makes.

", "

Now list1 is list2 is True, because there is only one list, and the two variables\nlist1 and list2 both refer to that same list. list1.append(4) appends to the one list\nand the result can be seen in both print(list1) and print(list2) because both lines\nare now just different ways of printing the same list.

\n

I recommend running both versions with Python Tutor to see how it visualises the difference.\nIn the second case, the two variables both have arrows pointing to a single list object.

\n

list2 = list1 doesn't create an eternal link between the variables. If you assign a new value\nto either of the variables, e.g. list1 = [7, 8, 9], the other variable will be unaffected\nand will still point to the original list.

\n

Basically, an assignment like:

\n
list2 = <expression>\n
\n

means 'make the variable list2 refer to whatever <expression> evaluates to'.\nIt doesn't make a copy of that value, which is how both variables can end up pointing to the same list.\nBut as we've learned before, list2 doesn't remember <expression>, only the value.\nIt doesn't know about other variables.

\n

You can copy a list with the copy method:

\n
list2 = list1.copy()\n
\n

This will make the program behave like the first version again.

\n

If you come across this kind of problem and you're still having trouble understanding this stuff, read the essay Facts and myths about Python names and values.

" ], "title": "== vs is" }, { "step_texts": [ "

Consider this program. It loops through a numbers and removes the ones smaller than 10. Or at least, it tries to. I recommend running it with Python Tutor.

\n
numbers = [10, 7, 8, 3, 12, 15]\nfor i in range(len(numbers)):\n    number = numbers[i]\n    if number <= 10:\n        numbers.pop(i)\nprint(numbers)\n
\n

(remember that numbers.pop(i) removes the element from numbers at index i)

\n

As it runs, it clearly skips even looking at 7 or 3 and doesn't remove them, and at the end it fails when it tries to access an index that's too high. Can you see why this happens?

\n

The index variable i runs through the usual values 0, 1, 2, ... as it's supposed to, but as the list changes those are no longer the positions we want. For example in the first iteration i is 0 and number is 10, which gets removed. This shifts the rest of the numbers left one position, so now 7 is in position 0. But then in the next iteration i is 1, and numbers[i] is 8. 7 got skipped.

\n

We could try writing the program to use remove instead of pop so we don't have to use indices. It even looks nicer this way.

\n
numbers = [10, 7, 8, 3, 12, 15]\nfor number in numbers:\n    if number <= 10:\n        numbers.remove(number)\nprint(numbers)\n
\n

But it turns out this does the same thing, for the same reason. Iterating over a list still goes through the indices under the hood.

\n

The lesson here is to never modify something while you iterate over it. Keep mutation and looping separate.

\n

The good news is that there are many ways to solve this. You can instead just loop over a copy, as in:

\n
for number in numbers.copy():\n
\n

Now the list being modified and the list being itererated over are separate objects, even if they start out with equal contents.

\n

Similarly, you could loop over the original and modify a copy:

\n
numbers = [10, 7, 8, 3, 12, 15]\nbig_numbers = numbers.copy()\n\nfor number in numbers:\n    if number <= 10:\n        big_numbers.remove(number)\nprint(big_numbers)\n
\n

Or you could build up a new list from scratch. In this case, we've already done a similar thing in an exercise:

\n
numbers = [10, 7, 8, 3, 12, 15]\nbig_numbers = []\n\nfor number in numbers:\n    if number > 10:\n        big_numbers.append(number)\nprint(big_numbers)\n
" ], "title": "Modifying While Iterating" } ], "user": { "developerMode": true, "email": "admin@example.com" }, "processing": false, "numHints": 0, "editorContent": "sentence = 'Hello World'\n\ninclude = False\nnew_sentence = ''\nfor char in sentence:\n if include:\n new_sentence += char\n include = True\n\nprint(new_sentence)", "messages": [], "pastMessages": [], "showingPageIndex": 16, "requestingSolution": false, "solution": { "tokens": [], "maskedIndices": [], "mask": [] } } } ```

alexmojaki commented 4 years ago

success!