HomeVideos

Programming Thinking

Now Playing

Programming Thinking

Transcript

3175 segments

0:00

This video teaches you programming

0:02

thinking.

0:04

People say you don't need to write code

0:06

anymore. You have AI.

0:08

I actually agree with that. But if

0:11

somebody say you don't need programming

0:12

thinking because of AI, I couldn't

0:15

disagree more. To say programming

0:17

thinking doesn't matter is like saying

0:19

basic knowledge and common sense don't

0:21

matter. We still went to school to learn

0:23

the fundamental of math, science,

0:25

economics because it helps us to think

0:28

and ask better question.

0:30

In the age of agentic engineering or

0:32

vibe coding, programming thinking is a

0:34

new common sense that help you to

0:37

maximize your use of AI. It's no

0:39

surprise to see the value created by

0:40

pure vibe coder just plateaus over time.

0:44

Whereas it's a people with programming

0:46

thinking can harness the true potential

0:48

of AI and create impactful project.

0:52

Throughout this video, we use a Python

0:54

language to learn about programming

0:56

thinking.

0:57

Starting from variable,

0:59

control statement, Python list, for

1:02

loop, loop with range, nested loop,

1:06

function,

1:07

value versus reference, dictionary,

1:11

and recursion.

1:12

Your attention is all I need. If you

1:14

invest your next 60 minutes in the

1:16

video, you'll transcend from a pure vibe

1:19

coder to the enlightened programming

1:21

thinker.

1:26

The first time when we saw equal sign,

1:28

it probably dates back in grade school.

1:30

1 + 1 = 2. The equal sign here feels

1:33

like a noun because it is statically

1:35

describing a math expression. And this

1:37

interpretation is buried deep within our

1:40

subconscious. Yet, in programming, the

1:42

equal sign means a complete different

1:44

thing. It's a verb. It's action which

1:47

you perform as a programmer. Using the

1:49

equal sign, we store a data into a

1:52

variable.

1:55

For example, hey, the variable whose

1:57

name is A, now you store the number

1:59

five. And if we print A, it's going to

2:02

print five. And we can use a variable A

2:04

as you were directly using a number

2:06

itself. So, A + 1 is basically 5 + 1, so

2:10

forth, A * 3, A to the power of 2.

2:15

We can also store a string to variable.

2:17

The variable whose name is B, now stores

2:20

a string Bob. If we print B, it prints

2:23

Bob. So, hello plus B is hello Bob. And

2:27

likewise, my name is plus B, B plus B

2:30

plus B.

2:34

Question. So, the variable thingy you

2:37

said here, what kind of data type? Is it

2:39

a number or is it a string?

2:41

Well, neither. The best way to think

2:44

about the nature of a variable is that

2:46

it is something that can store any data

2:48

type, but itself is not intrinsically a

2:50

data type. So, I know sometimes a

2:53

variable really looks like a string, but

2:55

it's not because it does not have the

2:56

quotes. For example, this is a variable

3:00

and the name of this variable is season.

3:03

But this season here is a string.

3:08

After you store a data to a variable,

3:10

which is action we call assignment

3:12

statement, you can use a variable later

3:14

as you were directly using a data stored

3:17

within.

3:18

Just knowing this fact, variable is

3:20

already a powerful tool. Potato was

3:22

using Python to calculate the surface

3:24

area and volume of a sphere. But now,

3:27

suppose the radius of a sphere is no

3:30

longer eight, but seven. He needs to

3:32

manually update all occurrences of eight

3:35

into the number seven and execute this

3:37

code again.

3:40

That's really not so efficient, right?

3:42

The more clever move here is to use a

3:44

variable. So, we first create a variable

3:46

on top. The variable's name is R. It

3:48

stores the number seven. And in our

3:50

formula, rather than multiplying with a

3:52

specific radius, we'll multiply that

3:54

with variable R, which we know now it is

3:56

seven.

3:57

And execute again. Great, this works.

4:00

From now, potato can just easily modify

4:03

the variable on top and you'll just

4:05

compute the answers for that particular

4:07

radius R.

4:09

At this point, some of you are like,

4:11

"Come on, potato. Don't be lazy. You are

4:13

only manually changing the number three

4:15

times. You don't need variables in your

4:17

life." But our potato could be more

4:19

ambitious. He's also interesting using

4:21

Python to compute the surface area and

4:23

volume of all the Platonic solid in this

4:26

world of the same edge length. They are

4:29

tetrahedron,

4:31

hexahedron,

4:32

octahedron, dodecahedron, icosahedron.

4:36

All the different type of hedron have

4:38

different formulas for surface area and

4:40

volume. But with the use of variable,

4:43

one modification here, every line of

4:45

computation below changes accordingly.

4:48

However, if you do want to replace all

4:50

occurrences of edge length manually,

4:52

it's very tiring. You get my point.

4:55

Let me interject with a few words about

4:57

terminology. With such an assignment

5:00

statement, variable A stores the number

5:02

five. Another 100% equivalent statement

5:05

is to say the value of A is five. I just

5:09

want to let you know that the two

5:10

description here means the exact same

5:12

thing. I would also use them

5:13

interchangeably.

5:15

Cool. Variables can store data. Variable

5:18

has value. Why don't we just call them

5:21

data container or value with a name?

5:25

Because a variable can store different

5:27

data throughout the execution of the

5:29

program. After your initial assignment

5:32

statement, you can change it again and

5:34

again. It can store the data of whatever

5:37

you want and changes whenever you want.

5:40

As a matter of fact, understanding how a

5:42

variable changes is a critical part of

5:44

programming. Hence, we need to be solid

5:47

on this topic.

5:49

So, I'm going to ask you to do the

5:51

following six quizzes.

5:53

I know your reaction. Wait a second. I'm

5:56

here to learn about Python variables.

5:58

Why are you already testing me?

6:00

Although this feel a little unfair at

6:02

the moment, I actually think it's a very

6:04

good idea to have you using your own

6:07

intuition to speculate how variable

6:09

behaves in Python and see where your

6:11

expectation misalign with outcome. This

6:14

is actually much better way of learning

6:15

and retain information.

6:17

Somewhere along the middle, you might

6:19

feel things start to get pretty boring,

6:21

but the mastery of variable is very

6:23

important. So, please stay with me

6:25

through the end.

6:28

I'll remind you one important fact.

6:30

Python program executes from top to the

6:32

bottom line by line.

6:35

Let's begin with a warm-up question

6:37

first. You can pause the video and

6:39

contemplate on what would this Python

6:41

program print out at the end.

6:44

Okay.

6:45

Hopefully, you have got your answer.

6:48

As the program executes from the top to

6:50

the bottom, the variables A, B, C, D

6:54

each stores its respective data.

6:57

On line number five, we have a string

6:59

concatenation, which begins with

7:01

variable A. We know that A is a string

7:03

Bob adding with has earned the string of

7:07

B * C * D, which is 5 * 8 * 20, 800, and

7:13

join again with this week. So, the final

7:16

output is Bob has earned $800 this week.

7:23

Quiz number one. You can go ahead to

7:25

pause and ponder on this Python program.

7:29

The answer here is pretty

7:31

straightforward. The variable is

7:33

initially assigned with a string that

7:34

says water

7:36

and then reassigned to the result of 2 +

7:38

1, which is 3, reassigned again to the

7:41

string fish, and then reassigned to the

7:43

number 500. But, what's the lesson here?

7:47

It is that a Python variable can change

7:49

between data types. The variable called

7:51

thing is initially storing a string, but

7:54

later it stores a number. Although this

7:56

may seem somewhat trivial at the moment,

7:58

yet in many other programming language

8:00

like C or Java, once a variable is

8:03

initially created to store number, it

8:05

can never be used to store a string

8:07

later on. Therefore, Python variable is

8:10

very flexible.

8:12

Number two.

8:14

The variable A stores seven, but in the

8:17

second line we create a variable B and

8:20

assign variable A to it. This is the

8:22

first time that a variable appears on

8:24

the right-hand side of the equal sign.

8:26

So, what exactly happens here? What does

8:28

B store?

8:29

The answer is B is going to store

8:31

whatever A stores.

8:33

A very common misunderstanding is that

8:35

people tend to have this mental image,

8:37

in which case we believe variable B is

8:39

storing the symbol of A, rather than the

8:42

value of A. That's incorrect.

8:45

When any variable is on the right-hand

8:47

side of the equal sign, we just treat it

8:49

as its value. Variable B stores the

8:52

value of A.

8:57

In line number four, variable B is

9:00

assigned as A plus 100. Since A is on

9:02

the right side of the equal sign, we

9:04

treat variable A as if we're treating

9:06

its value directly, which at the moment

9:08

the value is seven. So, B is a

9:10

reassigned as seven plus 100, 107.

9:14

In line six, C is assigned with B. So, C

9:17

is going to store the value of B.

9:21

In line number seven, D is assigned with

9:24

C. So, D also store 107.

9:28

So, the lesson here is all about

9:30

assignment of one variable by another

9:32

variable.

9:36

Number three.

9:38

Line one, variable n stores number 10.

9:41

Line two, the variable n appears on both

9:44

side of the expression, n equal to n

9:46

plus one. To be honest, this is

9:48

something strange to even look at. Then,

9:51

what's going on here?

9:53

Remember our principle that whenever a

9:55

variable appears on the right-hand side

9:57

of the equal sign, we treat it as if

9:59

we're directly treating its value. At

10:01

this point, n is 10. So, line number two

10:03

is basically saying n equal to 10 plus

10:06

one.

10:08

Line four, the variable n once again

10:11

appears on both sides of the expression.

10:13

But, we know we just need to treat it as

10:15

its value. At this moment, n is 11. So,

10:17

this line is saying n equal to 11 plus

10:20

one.

10:22

In line number six, n equal to n times

10:24

two, which is saying n equals to 12

10:26

times two. So, n is 24 now.

10:29

Whenever I see an assignment statement

10:30

looking like this, my brain

10:32

automatically translate this to plus one

10:35

to whatever its current value is.

10:37

And you might also see another way which

10:39

we can write this, and that is n plus

10:41

equal one. And those two statement you

10:43

see here, they are the exact same thing.

10:45

It's just a matter of personal

10:46

preference to choose either one of them

10:48

to use. So, the lesson of quiz three is

10:51

that a variable can update itself based

10:54

on its current value.

10:57

Number four.

10:58

The goal here is to once again test your

11:00

understanding of variable assignment. A

11:03

common misunderstanding would sound like

11:05

this.

11:06

In line number two, variable k is

11:08

storing the variable f. Therefore, if I

11:10

change k to zero, that means f is also

11:13

changed to zero.

11:15

But, that is incorrect.

11:17

I know that you know in line number two,

11:19

k equal to f is saying k stores a value

11:22

of f, which is 3,000. In line number

11:25

three, we change the value of k to zero.

11:28

But, that really had no business to do

11:30

with the original variable f. So, later

11:33

again, if we print F, it's still going

11:35

to be 3,000.

11:39

Number five.

11:42

So, what is the problem with this code

11:44

here?

11:45

Line number one and two executes

11:47

normally.

11:49

In line number three, we set area equals

11:51

to pi times radius squared.

11:54

What is the value of variable pi?

11:56

Oh, it's 3.14. It said that on the next

11:59

line.

12:00

But, remember Python program executes

12:03

from top to the bottom line by line. So,

12:05

at precisely the timing of line three's

12:08

execution, our computer has no idea the

12:10

value of pi.

12:12

So, there is actually going to be a

12:13

error. The lesson here, always define a

12:16

variable before using it.

12:20

Number six.

12:23

The last one we have here is a classic,

12:25

swapping two variables value. But, did

12:27

this code actually swap though? Nope.

12:30

The end goal here, after swapping, we

12:32

should see A is 99 and B is one. In line

12:36

four, A is assigned with value of B,

12:38

which is 99. So, the value of A is 99

12:41

now. In the following line, B is

12:44

assigned with value of A, which is also

12:46

99.

12:47

So, in the end, the value of the two

12:49

variables did not swap. They just both

12:52

became the value of B.

12:54

What code can we add so that in the end,

12:56

their values actually swap?

12:59

Perhaps you remember, after line number

13:01

four, when we reassign A with the value

13:04

of B,

13:05

the original data which A hold, the

13:07

number of one, is completely lost in the

13:09

environment of this program. Which

13:12

means, to fix this problem, we actually

13:14

need to create an additional variable

13:16

here, a variable called original A to

13:19

store A's original value

13:23

before A changes.

13:25

And later, rather than assigning B with

13:27

A, we assign B with a value of original

13:31

A.

13:37

And indeed, they're swapped. The lesson

13:39

here, when we want to swap two variables

13:41

in this manner, we need to be cautious

13:43

and we need to create an additional

13:45

variable for help.

13:49

Although I presented them as six small

13:51

quizzes, they in fact were six mini

13:53

lessons to go over the fundamental of

13:55

Python variable and assignment statement

13:58

while having you to use your own

13:59

intuition to speculate its behavior.

14:02

Did I spend too much time on the

14:04

details?

14:05

Absolutely not. Variable is such an

14:07

important concept. Many years down the

14:09

road, after you have written 1,000 lines

14:11

of code, you will have an unceremonious

14:13

realization that

14:15

wait, is programming just the art of

14:18

creating and updating variables?

14:23

And alas, let's finish with two remarks

14:25

about variable naming.

14:27

When coding, we really have freedom in

14:29

naming the variable we create. Yet, the

14:31

number one rule to follow is that

14:32

variable names should be meaningful.

14:35

Remember our warm-up question here? It

14:37

would make much more sense if I had to

14:39

use a more explicit variable naming.

14:42

See how the one down here feels like

14:44

this program is telling you exactly what

14:46

it is doing and it flows like an article

14:49

with high readability.

14:51

However, there is a few restriction on

14:54

variable naming. One is that we cannot

14:56

have any empty space within the

14:58

variable's name.

14:59

To fix that, we just replace the empty

15:01

space with an underscore symbol.

15:06

Another one is the first character of a

15:08

variable cannot be an integer, but we

15:10

could put integer anywhere afterwards.

15:14

At the moment, everything doesn't need

15:16

to be perfect. We're all beginners here.

15:18

If we make a mistake, the clever Python

15:20

interpreter is going to tell us where

15:21

the mistake happens.

15:23

We just need to go and fix it.

15:28

Today, we are going to learn about if,

15:31

else, and Boolean values. With their

15:34

help, our program gains ability to make

15:36

decisions, obtaining intelligence in

15:39

some way. As human, we really make

15:41

decision in a very subjective way, and

15:44

often times, we couldn't even precisely

15:45

explain our decision. We make decision

15:48

based on our mood, how tired we feel,

15:50

how hungry we feel, our friend's opinion

15:53

on certain matter.

15:55

Unlike humans, computer programs make

15:58

decision in the most objective way. It

16:00

evaluates the current condition. Is it

16:03

true?

16:04

Or is it false?

16:05

And nothing else. We call those two the

16:08

Boolean values.

16:10

You might wonder, Boolean, what a weird

16:13

name. So, they're actually named after a

16:15

famous logician, George Boole, who

16:18

believes true and false are the only two

16:20

values that's sufficient to describe all

16:23

the logic in this world.

16:26

The Boolean value is a new data type,

16:28

which can be stored by a variable.

16:30

If I print A, it prints true.

16:34

If I print B, it prints false.

16:37

Notice, true, false, they're both

16:40

capitalize.

16:42

Combined with if else, the Boolean

16:44

allows our program to make decision. I

16:47

think a demo is the best way to explain

16:49

this.

16:50

The behavior here is pretty

16:51

straightforward. Python still executes

16:53

from top to bottom.

16:55

In line number four, the if statement is

16:57

checking whether happy mood is true. And

17:00

now, it is.

17:02

When the if condition is true, our

17:04

program would execute the indented code

17:06

block under the if statement,

17:09

and will deactivate or completely ignore

17:12

the indented code block under else.

17:29

>> On the other hand, suppose happy mood is

17:32

false.

17:36

The if statement is facing a false

17:38

condition, and therefore, it would

17:40

deactivate the following indented code

17:42

block and go ahead to execute the else

17:45

part.

17:48

In short, using if else, our program can

17:51

take different actions based on

17:53

different conditions.

17:55

In the demo we just saw, there were a

17:57

piece of syntax we never seen.

17:59

Whenever we use if statement to check

18:02

for a condition, this line must

18:03

terminate with a colon, and the

18:05

following line must be indented.

18:08

Together, they're pretty much saying,

18:10

"This indented code block only belongs

18:12

to the statement here."

18:18

The indentation is a must, and there are

18:21

two ways you can do it. You can either

18:23

indent with one tap

18:26

or you can indent with four spaces.

18:32

Tap versus space, just who cares?

18:35

Surprisingly, many, many people. There

18:37

have been a long bloody war among the

18:39

programming community fighting over

18:40

which method is superior to indent your

18:43

code.

18:45

Linus Torvalds and Chris Latner are

18:47

perhaps two of humanity's most important

18:49

software engineer. One uses tap, the

18:51

other uses spaces. Personally, I'm

18:54

really in no position to imply which one

18:56

is better, so you pick your side from

18:58

here.

18:59

The values true, false, are two

19:02

intrinsic Boolean values,

19:04

but we can also have expressions that is

19:07

equivalent to true

19:09

or equivalent to false.

19:14

For example, the value of K is 1. K + 1

19:18

less than 5. This expression is

19:21

obviously correct.

19:22

If I print this, it actually prints

19:24

true.

19:25

If I change expression to K + 1 greater

19:28

than 5, then it prints false.

19:32

Those two symbols are what we call the

19:34

comparison operator because they

19:36

literally compare the left and

19:38

right-hand side, and the result is

19:40

comparison is always a Boolean value.

19:44

There are a few more of them.

19:46

We use this one to check for less than

19:48

or equal to.

19:49

This one for greater than or equal to.

19:52

The double equal sign to check for

19:54

equality.

19:56

The exclamation equal to check for

19:58

inequality.

19:59

1 + 1 is equal to 2. This expression is

20:03

true.

20:04

1 + 1 is equal to 3. This expression is

20:07

false.

20:09

The string of three is equal to the

20:10

number three.

20:12

False. And therefore, it is true to say

20:15

they are not equal.

20:17

The value of A is a string that says

20:20

protein.

20:21

If A is equal to the string fat, then we

20:24

print they're equal.

20:26

Else, we print not equal.

20:29

You might wonder, it's pretty weird to

20:31

write two equal sign next to each other.

20:33

Why can't we just use the one equal sign

20:35

to check for equality?

20:37

Remember, we have already reserved the

20:39

single equal sign exclusively for

20:41

variable assignment. Therefore, we must

20:44

use something different for actually

20:45

checking equality.

20:53

In the video game The Legend of Zelda,

20:55

the currency is called rupee.

21:01

Suppose our main character has

21:03

absolutely no money now. So, we set the

21:05

variable money to zero.

21:08

But, he finds a chest box. If the item

21:11

in the box is actually a green rupee,

21:13

which has a value of one in this

21:15

currency system,

21:17

our character has money now, and we

21:18

increase his money by one.

21:21

But, oftentimes the item is something

21:23

else, such as food,

21:25

weapon, minerals.

21:27

In those cases, the main character need

21:30

to sell the item in exchange for rupee.

21:33

Perfect. This code uses if else to

21:36

express the logic we have.

21:38

If I change the item to sword, then our

21:40

character has zero money.

21:44

Mhm, there is one issue. In this game,

21:47

there are also rupees of other colors, a

21:50

red rupee worth 20,

21:52

or if you get super lucky, there is the

21:54

gold rupee, which worth 300.

21:57

So, suppose you are the game developer,

21:59

how do you change this program to

22:01

include more conditions?

22:04

One easy way is to use the elif

22:06

statement, which stands for else if.

22:09

You can think of elif as an additional

22:12

checking of condition in between if and

22:15

else.

22:18

In our case, if the item is not a green

22:21

rupee, rather than directly skipping to

22:23

the else part, we can use the elif to

22:25

check if the item is a red rupee.

22:28

And after that, another elif to check if

22:31

the item is a gold rupee.

22:34

In summary, the elif statement give us

22:36

more condition to evaluate in the

22:38

process of decision-making.

22:43

In this game, we can also eat things to

22:45

restore health.

22:46

But, whenever we're trying to eat

22:48

things, the gaming system is first going

22:50

to check if the thing is actually

22:52

edible.

22:53

So, please take a moment to consider

22:55

this code right here.

23:01

As ST meat skewer is edible.

23:07

An ancient gear is not.

23:10

So a simple if else will check for this

23:13

logic.

23:14

But actually even if our item is edible,

23:17

it doesn't mean we can consume it right

23:18

now. There is one more condition to be

23:21

met, which is our character cannot be

23:23

full health.

23:25

If the character's maximum health is

23:27

four, then his current health must be

23:29

less than four in order to eat food.

23:32

So how can we encode this logic into our

23:35

program?

23:38

Our attempt is to add another pair of if

23:41

else within the first if condition.

23:43

So notice this line is actually indented

23:46

twice.

23:47

You can think of this logic here is

23:49

saying something like this.

23:51

If the item is edible, then it still

23:53

needs to go through this entire

23:55

evaluation procedure again.

23:57

If our food is not edible, then it just

23:59

skip to the else part.

24:02

Wait. Line seven, the condition here is

24:05

clearly true. Our current health is 2.5

24:08

and the maximum health is four. So why

24:11

is line number eight not executing?

24:14

Very good question. The key property of

24:17

if statement inside another if statement

24:19

is that whenever you want to check for

24:21

an inner condition, the outer condition

24:23

must be true first. If the outer

24:25

condition is false, it doesn't matter

24:27

how true the inside is because the

24:29

program will just never go in there.

24:34

So if I change the food back to zesty

24:36

meat skewer, then the character can eat

24:38

it.

24:39

But if I change the current health to

24:40

four, then he cannot.

24:44

Whenever we have if inside another if,

24:47

this is called a nested if statement.

24:50

Honestly, when I first learned a Python,

24:52

nested structure was pretty hard for me

24:54

to comprehend. The only way out is

24:57

just doing some coding exercise.

25:00

And I'll take a moment here to compare

25:01

and contrast between elif versus nested

25:04

if.

25:05

Initially today, the only thing we know

25:07

about is if else.

25:10

The use of elif is much like adding a

25:12

new path in between them.

25:14

When the condition for if is false, elif

25:17

give another condition to evaluate

25:19

before jumping straight to the path of

25:21

else.

25:24

The use of nested if is much more like

25:26

extending an additional path from the

25:28

existing one.

25:30

Suppose we want to get here, the only

25:32

way is for the outer condition to be

25:34

true.

25:35

And after that, the inner condition is

25:37

also true.

25:41

Often times, certain action can only be

25:43

taken if two conditions are true at the

25:45

same time. In the game, even a simple

25:48

action such as shooting an arrow

25:50

requires two conditions to be true.

25:54

One, we need to have a bow. Two, we need

25:56

to have at least one arrow.

26:00

This is where logical operators comes in

26:02

handy. The logical operator and allows

26:05

us to create a Boolean expression that

26:07

is only true when both condition on each

26:09

side are true.

26:11

If either condition is false, then the

26:13

overall expression evaluates to false.

26:21

This expression would evaluate to false.

26:23

Four is equal to four. True.

26:26

Zero is greater than zero. False.

26:29

True and false would evaluate to false.

26:34

Therefore, we can use the and operator

26:36

to encode our logic for shooting arrow.

26:39

If has bow is true and arrow counts is

26:41

greater than zero, then we shoot arrow.

26:44

Else, we cannot.

26:48

Changing the variable has bow to false,

26:50

the program outputs cannot shoot arrow."

26:54

If we're really being serious, we should

26:55

also decrease the main character's arrow

26:57

counts by one because he just shot it.

27:04

In contrast to and, there is the or

27:07

logical operator. The or creates a

27:09

Boolean expression that evaluates to

27:11

true as long as either one condition is

27:14

true.

27:23

One way to compare them is that and is

27:26

very strict. Both conditions need to be

27:28

true for the expression to be true. Or

27:30

is kind of soft. As long as one

27:32

condition is true, it is true overall

27:34

and it doesn't care which one is true.

27:38

When our character explores cold area,

27:40

he actually lose health points for being

27:43

physically exposing low temperature.

27:45

But, as long as he's either wearing warm

27:47

clothes

27:48

or he ate spicy food. Apparently, in the

27:51

game, eating spicy food give you cold

27:52

resistance. He no longer takes damage

27:55

from the cold weather.

27:57

This is a good application for the or

27:59

logical operator. If has a warm cloth or

28:03

ate spicy food, the character is staying

28:05

warm. Else, he's taking damage from the

28:08

cold weather.

28:14

You might hear the term short-circuiting

28:16

when people describe the evaluation for

28:18

chain of condition in Python.

28:20

It's natural to suspect how does

28:22

Python's logical operator and or ever

28:26

relate to a physical circuit? Although

28:28

the next part of the video does not help

28:30

with your understanding of Python, but

28:33

is pretty cool. So, I got to show you

28:34

their connection.

28:36

To begin with, suppose we have a Boolean

28:38

value true.

28:40

We can represent this as a closed gate

28:42

where electrons flows through.

28:46

If the Boolean is false, then it will be

28:49

seen as an open gate where electrons

28:51

doesn't get to flow through.

28:54

Now, here is a cool thing. Suppose we

28:57

have two Booleans, we AND them together.

29:00

This is essentially putting the two

29:02

gates in series. The only way the

29:04

electrons can flow through is for both

29:06

gates to be closed. If either one gate

29:09

is open, the electron gets stuck in the

29:11

middle, which corresponds to the

29:13

expression evaluating to false.

29:17

On the other hand, if we OR the two

29:19

Booleans, it's like putting the two

29:21

gates in parallel. As long as one gate

29:24

is closed, doesn't matter which one,

29:26

electrons can flow through the end. When

29:29

both gates are open, that's when the

29:31

expression is false.

29:35

When we have a long chain of AND

29:37

condition together, it is essentially a

29:39

chain of gates in series.

29:41

If one gate is open, electrons cannot

29:43

flow through.

29:47

When we have a long chain of OR

29:48

conditions, the gates are parallel

29:50

together. As long as one of them is

29:52

closed, the electrons will be able to

29:54

flow through.

29:57

The lesson today was a lot of

29:59

information. I'll give a quick summary.

30:01

We first learn about the Boolean values,

30:03

the if else statement. At this point,

30:06

our program already has ability to make

30:08

simple decisions.

30:10

And then, there were the comparison

30:11

operators, logical operators, which

30:14

allows us to create Boolean expression

30:16

that ultimately evaluates to true or

30:18

evaluates to false.

30:20

With the help of elif and nested if, our

30:23

program can behave properly when there

30:25

are multiple conditions or there's

30:27

dependency between conditions.

30:30

Using all of them combined, we can

30:32

pretty much describe any software design

30:35

logic, and George Boole will be proud of

30:37

you.

30:43

Python list is a very powerful data

30:46

type. A list is like a chest box of

30:48

data. You can store any numbers of data

30:50

in there and retrieve them later

30:52

whenever you want.

30:53

But I know you behind the screen is

30:55

clearly someone clever. If I just read

30:58

over the documentation word by word,

31:00

it's boring. So instead, let's begin by

31:02

telling a story about the history of

31:04

poker suits using Python list.

31:08

Way back in the 14th century, the suits

31:11

of the playing cards in Spain were

31:13

nothing but familiar. The four suits

31:15

were cups, coins, clubs, swords.

31:19

The suits, which you and me are familiar

31:21

with, hearts and diamond, were not in

31:24

there.

31:25

Yet, it was true that clubs wasn't

31:27

there.

31:29

People decided to make things more

31:31

interesting by introducing an additional

31:33

suit, which is called shields.

31:37

And there were five different suits in a

31:39

deck.

31:40

Many decades later, the Germans decided

31:43

to build their own deck by starting from

31:45

scratch.

31:48

They added the suits hearts, bells,

31:51

acorns, and leaves.

31:53

And those four suits gained immense

31:55

popularity in Europe, but of course, not

31:58

as popular as its successor. The French

32:00

suits drew inspiration from the German

32:02

suits. They kept the hearts, but removed

32:05

the bells.

32:08

They replaced acorn with clubs and

32:11

replaced leaves with spades.

32:15

And finally, they added in the diamonds.

32:18

Hearts, clubs, spades, diamonds. They

32:21

survived all the way to the 21st

32:23

century.

32:25

All right, that was a lot of

32:27

informations. Let's take a moment to

32:28

dissect on what just happened. To create

32:31

a Python list, we use a square bracket

32:33

on a keyboard. If you ever wonder what

32:35

those weird-looking brackets are for.

32:37

They're used by programmers.

32:39

Normally, we create an empty list

32:40

without any data in there.

32:43

We can also create a list with some

32:45

initial data. We will use the comma to

32:48

separate them, distinguishing data from

32:50

datas.

32:51

Sometimes, people use the word element

32:53

referring to a particular data in a

32:55

list. I'll use those two terms

32:57

interchangeably in this video, too.

33:00

Here, you definitely notice something

33:01

strange. The variable my list does not

33:04

store the entire list, which is what

33:06

everyone expected. But, rather, it is

33:09

storing an arrow which reference to the

33:11

actual list. Why? Strange, indeed.

33:15

In later chapter called value versus

33:17

reference, we'll have a much more

33:19

in-depth conversation about this and

33:21

understand why it's really important.

33:24

For now, it's good to have this mental

33:26

image. Variables such as number, string,

33:28

boolean, the actual data is stored.

33:31

But, a list variable only stores a

33:33

reference to the actual list.

33:37

After creating list, much of your

33:39

programming interaction with Python list

33:41

stems from these four primary

33:42

operations.

33:44

Access,

33:45

modify,

33:47

add,

33:48

remove an element from the list.

33:51

Zero and foremost, when we want to

33:53

access an element from a list, we must

33:55

know its index. For example, suppose I

33:58

want to get a first element, assign it

34:00

to the variable called item. We use the

34:02

name of the list,

34:04

square bracket, index zero.

34:10

Yep, what you see is correct. To get the

34:12

first element, we don't use number one,

34:14

we use the number zero. We call this

34:16

behavior zero indexing. This is pretty

34:19

important to emphasize again. The human

34:22

understanding of first actually

34:24

translates to index zero in Python.

34:28

You cannot imagine the number of human

34:30

intelligence hours that had been wasted

34:32

on this bug. Somewhere inside a massive

34:35

software, a programmer is trying to

34:36

access the first element, but the index

34:39

one is used instead of zero, causing the

34:41

entire program to behave incorrectly.

34:45

Now, here's a question for you. Suppose

34:47

I want to get a third element of a list,

34:50

which index would you use?

34:54

Index two.

34:56

So, the pattern is whenever you want to

34:58

access the nth element, the index used

35:01

is n minus one.

35:04

The action of modifying a particular

35:07

element feels almost identical to

35:09

modifying a variable.

35:12

We can modify any variable simply by

35:13

reassigning it to something else.

35:17

In the element case, we just reassign

35:19

the list index to something else. The

35:21

first element of crypto list is Bitcoin,

35:23

and I want to change the first element

35:25

to Litecoin.

35:26

I just write crypto list index zero

35:30

equal the string Litecoin.

35:35

A variable can update from its existing

35:39

value.

35:40

So can an element inside a Python list.

35:43

This code here updates the third

35:45

element, which is index two, by

35:47

multiplying 1.2 with its existing value.

35:56

Suppose I want to modify the element

35:58

Bitcoin to Litecoin. Does this code

36:01

snippet here do the job for me?

36:05

It looks like it does, but it doesn't.

36:08

The only thing we did here was to change

36:10

the variable coin.

36:12

The element of index zero was never

36:14

changed.

36:15

A pretty easy place to make mistake if

36:17

we're not careful.

36:21

When we want to add a new element to a

36:22

list, we use the append method.

36:26

Pretty straightforward. The string Kyoto

36:29

is now added to the end.

36:32

Wait, this is a new syntax we never

36:34

seen. What is a dot doing in the middle?

36:38

So, this is called a method. In later

36:41

chapter, we will formally define what a

36:43

method is.

36:44

This syntax is pretty much just saying,

36:47

after the dot symbol, we're doing some

36:49

action, and whatever the action is is

36:51

directly related to the item here.

36:56

One thing notable to mention, when we

36:58

append a variable to a list, we're

37:00

appending its value rather than a

37:02

symbol. The variable place stores a

37:04

string Kyoto. If we append place to

37:07

travel list, the string of Kyoto is

37:09

added to the end.

37:13

However, if this is your mental image,

37:16

you'll be incorrect.

37:23

So, yeah. If this feels like déjà vu,

37:25

it's because we really emphasized this

37:27

concept back in chapter two.

37:30

When we want to remove element, we use

37:33

the pop method.

37:35

By default, pop removes the last element

37:37

from a list.

37:39

We can also give it an index, and that

37:41

particular index element will be

37:43

removed.

37:46

Sometimes we don't know the index of the

37:48

element we want to remove. Suppose we

37:50

have a list of vegetables. One day, I

37:52

find out tomato is not vegetable. Tomato

37:55

is actually fruit. We want to remove

37:57

fruit from vegetable list, but we don't

38:00

know the exact index of tomato. Frankly,

38:02

we don't really care about its index, we

38:04

just want to remove it.

38:06

We use the remove method. We just need

38:08

to specify the data we want to remove,

38:11

not the index.

38:12

Our Python list will find it and remove

38:14

it for us.

38:18

Even after learning those four primary

38:20

operations, you might still feel there's

38:22

nothing that special about Python list.

38:25

So, it's time to expand our imagination

38:27

to something bigger. How about a Python

38:29

list that contains every word in Romeo

38:33

and Juliet?

38:37

So, I first Google Romeo and Juliet txt

38:40

and there's a good website hosted by

38:42

MIT. And I just copy this entire thing

38:45

and paste it on my Google Colab.

38:49

Now,

38:50

I'm going to use the triple quotation

38:52

mark in the very front

38:54

and the very end to enclose this entire

38:58

chunk of text.

38:59

This thing now is actually one valid

39:01

Python string. Look at the color. It's

39:04

yellow.

39:05

Which I can assign this to a variable

39:07

called RJ text stands for Romeo and

39:09

Juliet.

39:11

Triple quotation mark is another valid

39:13

way to create a Python string. The

39:15

reason we don't use single quotation

39:17

mark, which is what we always do, is

39:19

because there are new lines within this

39:21

text

39:22

and there could also be existing

39:24

quotation mark in there as well.

39:27

Allow me to inject a quick lesson on

39:29

string manipulation. Although these new

39:31

methods seem somewhat overwhelming, but

39:33

in fact, they're just performing very

39:35

simple action. The dot lower method

39:38

creates a new string after turning every

39:40

single character into lowercase.

39:43

The dot replace method creates a new

39:46

string, in our case, after replacing all

39:48

occurrences of comma with an empty

39:50

space.

39:55

The dot split method, which uses a

39:57

Python string to magically create a

39:59

Python list. Any empty space in the

40:02

string indicates boundary between

40:04

elements.

40:08

Coming back, we first use the lower

40:10

method to create a lowercase string of

40:12

Romeo and Juliet.

40:13

Then, we replace all all punctuation

40:15

mark with empty spaces

40:17

And assign this to the variable

40:19

RJ_text_no_pmark.

40:21

Of course, there are other punctuation

40:23

mark besides commas. So, we update the

40:25

variable text_no_pmark based on its

40:28

existing value, but further replacing

40:30

out all the period marks.

40:32

And we repeat the same process for the

40:34

rest of them.

40:36

And then finally, we use the split

40:38

method to create a list version of the

40:40

string.

40:42

If I print RJ_list, what I see is a long

40:45

long Python list.

40:48

This list contains every single word of

40:50

Romeo and Juliet, which is what we want.

40:52

Let's ask some basic questions. What's

40:54

the first word in there?

40:58

What's the second word in there?

41:02

What's the 500th word in there?

41:06

I can use the l e n len function to

41:09

check for how many elements this list

41:11

have.

41:12

This thing is a number, so I can assign

41:14

this to a variable and print it.

41:18

Our list has 25,000 strings in there.

41:22

Besides the comparison operator, the in

41:25

keyword is another tool we have to

41:27

create a boolean expression by asking if

41:29

a certain data is indeed within the

41:31

list.

41:34

We can ask, is the string Romeo in

41:37

RJ_list?

41:38

How about the string Juliet?

41:41

False.

41:42

Oh, it's because I misspelled Juliet.

41:45

Is Shakespeare's iconic thou in there?

41:49

Is the word love in there?

41:51

False.

41:52

How come? I thought this is love story.

41:55

It's because I made a mistake. Remember,

41:57

everything has been turned into

41:58

lowercase, so it's impossible for any

42:01

capitalized string to be found within

42:03

RJ_list. I need to lowercase love as

42:05

well.

42:08

Is the string poison in there?

42:11

Since the in keyword us a boolean value,

42:14

so we can write a if-else logic.

42:18

The string robot is not in there.

42:20

The string Python is also not in there.

42:23

See, we don't even need to read the

42:25

entire thing. We can conclude that the

42:27

story is not about robot nor Python.

42:34

If anyone ask me what's the most

42:36

important concept in basic programming,

42:39

I would say for loop.

42:41

However, for us beginners, the first

42:43

time seen this idea, it seems really

42:45

abstract and non-intuitive. So, let's

42:48

motivate this concept with a real-world

42:51

example. Potato is working as a software

42:53

engineer for Google now. His job is to

42:56

print out every element of a Python list

42:59

while saying hi.

43:00

And he wrote this program.

43:02

Potato's clever solution is to access

43:04

the first element and assign it to the

43:06

variable user

43:08

and print hi user.

43:10

After that, the variable user changes to

43:12

the second element and print hi user.

43:15

And after that, user changes to the

43:17

third element and prints hi user again.

43:20

And finally, he prints work done, going

43:22

home.

43:24

As you can see, Potato's overall

43:26

strategy is to create just one variable,

43:29

user.

43:30

And he keeps recycling this variable by

43:32

manually changing it to the next index

43:34

and then print hi user. His program

43:36

executes perfectly. Good job, Potato.

43:39

Everything is fun and games until this

43:42

list starts to get really long. One

43:44

morning, Potato realized user list has

43:47

5,000 elements.

43:50

Does it imply he's going to write code

43:52

like this?

43:53

I mean, this works, but our Potato is

43:55

definitely exhausted.

43:58

Looking at his 6-hours long effort,

44:00

Potato realized that his code is

44:02

extremely repetitive. He is essentially

44:04

just printing hi user over and over

44:07

While the variable itself changes to the

44:09

next one and to the next one and to the

44:11

next one.

44:13

He wonders, what if the variable user

44:16

can be a little smarter such that it

44:18

changes on its own to the next element

44:21

one by one.

44:23

So that I only need to write hi user

44:25

once.

44:27

And this is the entire premise of for

44:30

loop, which is to automate the

44:32

repetitive simple actions finding small

44:34

patterns to solve big problems. Now,

44:37

potato writes

44:39

for user

44:41

in user list colon

44:44

indentation

44:45

print hi user.

44:47

With this type of syntax, a for loop

44:50

begins.

44:53

The loop variable user is just going to

44:56

change on its own, hopping to the next

44:58

element, changes its value to that,

45:01

hopping to the next element and changes

45:03

again. Every time after user change the

45:06

next element, the entire indented code

45:08

block under the for statement will be

45:10

executed.

45:12

The for loop is going to repeat this

45:15

change execute change execute change

45:17

execute alternating actions tirelessly

45:21

all the way to the end. There is a

45:23

sensation that the for loop is running.

45:27

No matter how long this Python list is,

45:29

whether it's 50 elements, 50,000

45:32

elements, or 50 million elements,

45:34

potato's program would run properly.

45:41

A few syntax to point out. Remember in

45:43

the previous chapter, we learned that

45:45

the in keyword can check whether data is

45:47

indeed inside a list. The same in also

45:50

appears when we're writing for loop. I

45:52

just want to say those two in means

45:55

complete different things under the two

45:57

different contexts.

45:58

This in is more like asking a question.

46:02

Is it in there?

46:03

This in is more like a statement saying

46:06

that the loop variable user will change

46:08

its value one by one to every element

46:11

inside the list.

46:13

Once again, we see the familiar colon

46:16

and indentation syntax, which we had

46:18

previously seen with if else statement.

46:20

Only the indented code block will be

46:23

executed repeatedly when the loop is

46:25

running. Things outside a for loop will

46:28

not be a part of the loop action.

46:30

And this indented code block can

46:32

definitely be well more than one line.

46:36

Up next, we're going to get ourselves

46:38

more familiarized with for loop by

46:40

tackling three coding tasks while

46:42

highlighting some common mistakes and

46:44

misconceptions along the way.

46:46

Suppose we have a list of numbers. This

46:49

list can be short or very long.

46:53

Your goal is to find out what's the

46:55

summation of the list or if we literally

46:58

add all the numbers together, what would

47:00

it be?

47:02

If you've never seen a question like

47:04

this before, I promise you the answer

47:06

will be non-obvious. So, for sure take a

47:09

moment to pause and ponder.

47:14

So, the central idea is to create a

47:16

variable outside before the loop starts

47:19

running. We initialize the variable S to

47:21

zero.

47:23

When the for loop is running, we keep

47:25

adding values into the variable S.

47:35

Currently, the loop variable number is

47:38

100. The code block to execute is S

47:41

equals to S plus number, which means we

47:43

update S by adding 100 to it. So, S

47:46

becomes zero plus 100, which is 100.

47:50

After that, the variable number hops to

47:52

the next one. Number changes value to

47:55

five. The value of S at this point is

47:57

100. We increase it by 5. So, S becomes

48:02

105. Of course, the variable number hops

48:05

onto the next one again and updates S

48:07

again.

48:09

This process repeats. So, the variable S

48:12

is getting bigger and bigger by

48:14

accumulating all the index the loop has

48:17

passed through.

48:18

By the time when the loop terminates,

48:20

the variable S has already collected all

48:22

the values along the way.

48:26

Pretty ingenious, right?

48:30

The variable S is a critical data we

48:33

want to update in the midst of a for

48:34

loop. A very common mistake, which I

48:37

definitely made often, is that we put

48:39

the variable S inside a for loop rather

48:42

than the outside.

48:43

Let's see why this is a big problem.

48:52

S equal to zero. Since the variable S

48:55

does not exist yet, this means we're

48:57

going to create the variable S and

48:59

initialize it to zero.

49:00

S equal to S plus 100, so S becomes 100.

49:04

So far, so good. Number hops to the next

49:07

element. As you can see, the line S

49:09

equal to zero is within the indented

49:12

code block. So, it's going to get itself

49:14

executed every time.

49:16

S is reset to zero.

49:18

But, what about the 100 we had seen

49:20

before?

49:21

It's not accumulating anything.

49:24

Even when this loop reaches to the end,

49:26

the variable S does not remember

49:28

anything it seen before. Obviously, this

49:30

is a problem.

49:33

So, the lesson here is we have to be

49:35

really cautious about what variable to

49:37

put inside versus the outside of a for

49:40

loop.

49:44

All right. Spent a long time on the

49:46

previous one.

49:47

Task two. Suppose we have a list of

49:49

natural numbers.

49:51

How can we find the biggest number in

49:53

there?

49:57

The solution, once again, is that we're

49:59

going to create a variable outside the

50:01

for loop called the current max. The

50:03

idea is to have this current max

50:04

variable to store the biggest number the

50:07

loop has seen so far. So, it's

50:09

initialized to the smallest natural

50:11

number.

50:17

As the loop starts running, we use a

50:19

condition statement to check whether we

50:21

should change current max.

50:23

For example, at this moment, loop

50:25

variable number is 17, and current max

50:28

is five. 17 is bigger than five, but

50:31

this also means that the current element

50:33

is bigger than every single element the

50:35

loop has yet seen. So, we must change

50:37

the value of the current max to 17.

50:43

On the contrary, if the value of number

50:45

is less than current max, for example,

50:47

number is 12 and current max is 17. That

50:50

means there definitely exists an element

50:53

somewhere before the current index it is

50:55

bigger than 12. So, we don't change

50:57

anything and move forward.

50:59

As the loop reaches through the end, the

51:01

variable current max has been compared

51:03

with every single index. Every time when

51:06

current max faces a larger number, it

51:08

changes to that. So, by the end, current

51:10

max certainly stores the biggest number

51:12

in this list.

51:18

Common question one, do I have to name

51:20

the loop variable as number?

51:22

Nope. You have complete freedom in

51:24

choosing the variable name. You can also

51:26

name it current element or just cur

51:30

or even c.

51:32

As long as you use them consistently,

51:35

it's going to work.

51:37

Common question two, when the loop

51:38

terminates, namely outside the loop's

51:41

indentation, can I do something about

51:43

the variable c? Like, can I print it?

51:45

So, we cannot. The loop variable is kind

51:48

of like a ephemeral variable that only

51:50

exists when the loop is running.

51:53

When the loop terminates, the variable C

51:56

just vanishes after having done all its

51:58

work. It disappears completely from the

52:00

environment of our program. Outside the

52:02

for loop, we cannot do anything about

52:04

this variable.

52:09

Suppose you and many friends are going

52:11

on a road trip. You surveyed everyone

52:13

for movies to watch together as a group.

52:15

You asked them to append their own

52:17

favorite movie to the list.

52:19

And since certain movies are really

52:20

popular, this list has some

52:22

redundancies.

52:24

As a group leader, you don't want to

52:25

bore everyone by asking them to watch

52:27

the same movie twice. Your goal is to

52:30

create another list in which every

52:31

element is unique. Or every movie only

52:34

appears in there once.

52:40

The idea is similar. We create an empty

52:43

list outside. As the for loop starts

52:45

running, we conditionally append movies

52:47

in there.

52:48

Since I never touch on this not logical

52:50

operator, let me inject a quick lesson

52:52

on this.

52:53

Suppose I have a Boolean true.

52:56

By putting not in front of it, it

52:57

negates to false.

52:59

By putting not in front of false, it

53:01

negates to true.

53:04

The thing on top is a Boolean expression

53:06

that evaluates to true.

53:08

By putting not in front of it, it

53:10

evaluates to false.

53:21

As the loop begin, the variable MV

53:24

stores a string Endgame.

53:26

By our design, unique list cannot have

53:28

any redundant element. We only append

53:30

new movies in there if it is currently

53:32

not in unique list.

53:34

At the moment, unique list is empty and

53:36

Endgame is not in there. We append.

53:39

Hopping to the next one. Spider-Verse

53:42

not in unique list. True, we append.

53:46

Next one.

53:47

Endgame is already in there, we do not

53:50

append.

53:51

So, if my verbal commentary of four

53:53

loops start to get pretty monotonous and

53:55

predictable for you,

53:57

hey, yeah, you start to really

53:59

internalize four loop now.

54:06

Looking back at our journey so far, we

54:08

attempted to define a word programming.

54:11

In chapter zero, we said programming is

54:13

creating interesting things. In chapter

54:16

two, we said programming is art of

54:18

changing variables. Today, the

54:20

definition is more refined. Programming

54:22

is art of changing variable in the midst

54:24

of running four loop with conditional

54:26

statement.

54:27

The reason why I cherry-picked those

54:29

three particular examples, because on

54:31

one hand, I think it really drives this

54:32

thesis home. On the other hand, there's

54:34

some concrete setting for us to engage

54:36

with programmatic thinking. Rather than

54:38

just using four loop to print out Python

54:40

list elements. Four loop is about

54:42

finding small pattern to solve big

54:44

problem using their few lines of code to

54:46

work with a list of data that could be

54:48

unimaginably long.

54:51

In many future coding situation, I

54:53

promise you that you can find archetype

54:55

of thinking stemming from these three

54:57

examples.

54:59

Next chapter, we'll learn about a more

55:01

generalized technique of looping, and

55:02

we'll see many beautiful connections

55:04

between coding and mathematics. See you

55:06

there.

55:11

In the previous chapter, we learned that

55:13

whenever there's a Python list, we can

55:15

use a four loop. The four loop is a

55:18

great method for automating repetitive

55:20

and simple actions.

55:23

The loop variable keeps hopping onto the

55:25

next element, changes value to that, and

55:28

the indented code block executes. Those

55:30

action repeats. There is a sensation

55:33

that the four loop is running.

55:38

As programmer, we call this running a

55:40

for loop over a list or simply looping

55:43

over list.

55:44

But a more professional way to call this

55:47

is iterating over a list. As vocab,

55:50

iterate means to do again, do again, do

55:52

again.

55:54

Yet, Python list is not the only thing

55:56

that can be iterated over. In fact, it

55:59

belongs to a larger abstract class of

56:00

objects called iterable.

56:03

I know this entire playlist is aimed for

56:05

beginners, so we're not going to the

56:07

details about what exactly this word

56:09

mean. So, for now, if I tell you

56:11

something is an iterable, that means it

56:14

can be a target of for loop. And the

56:16

range object is an iterable.

56:19

By calling the range function with a

56:21

start and end index, we get a range

56:24

object.

56:25

But what exactly is this range object?

56:28

You can basically think about it as a

56:30

sequence of numbers that can be loop

56:32

over.

56:34

When the for loop starts, the loop

56:36

variable I iteratively binds to all

56:38

integer from 0 to 9.

56:42

As you see, when we loop over the range

56:44

object, it logically just feels like

56:46

we're looping over a Python list, which

56:48

contains the sequential integers.

56:54

Notice range 0 10 does not give you the

56:57

number 10. It only gives you all the

56:59

number from 0 to 9.

57:01

This is because Python's end index is

57:04

always non-inclusive. If we want the

57:06

number 10 in there, we have to change

57:08

this to range 0 11.

57:13

So, what exactly can we do about this

57:16

range object? A sequence of numbers

57:18

doesn't seem any useful at all.

57:21

We can use the range to indirectly loop

57:24

over another Python list.

57:29

For the range object, the start index is

57:31

0 and the end index equals to the length

57:34

of the list.

57:38

As the for loop begins, the loop

57:40

variable I is integer,

57:42

but it conveniently also represent the

57:44

index of my list. Then, we can access

57:47

the corresponding element using this

57:49

index

57:50

and store it into variable var

57:53

and print it.

57:55

Since we're iterating over all the

57:57

indices, we ensure that every element is

58:00

visited. What you see now is another

58:03

perfect valid way of looping over a

58:05

list.

58:14

So, let's take a moment to compare and

58:16

contrast between the two strategy of

58:18

looping.

58:19

In the direct method on left, the loop

58:22

variable var directly binds to the

58:24

element, and we can use it immediately.

58:27

On the right, the indirect method, where

58:29

looping over a sequence of numbers,

58:32

the loop variable I only binds to an

58:34

integer, and then we use the integer as

58:36

the index to access the corresponding

58:39

element.

58:40

So, this one here is a two-step process.

58:44

Potato's like, "The indirect method is

58:46

so inefficient. Why would anyone ever

58:48

want to loop over a bunch of indices?

58:51

Just do it directly."

58:53

Thank you, potato. That's indeed a very

58:55

good question. It turns out looping over

58:58

indices has the advantage in certain

59:00

cases.

59:01

Consider this scenario. We have a list

59:04

of numbers, which stores the hourly

59:06

salary of six different employees,

59:09

and we want to increase everyone's money

59:11

by $5.

59:14

Potato's like, "Easy. Gotcha." He writes

59:17

a Python code for salary in salary list,

59:20

salary equal salary plus five.

59:25

As the loop begin,

59:27

you already see the problem.

59:30

The only thing that this code is doing

59:32

is just increment the loop variable

59:34

salary by five.

59:36

But the actual element in salary list is

59:40

never changed.

59:42

Therefore, this code is incorrect.

59:46

So, to fix that, we must use the

59:48

indirect method, loop through the

59:50

indices of the list.

60:01

As the for loop begin, the loop variable

60:03

I iteratively binds to all the index of

60:06

salary list, and we increase the element

60:10

sitting at index I by five.

60:13

Here, we clearly see the data inside the

60:16

Python list has been changed.

60:19

So, the lesson is if we want to modify

60:22

the actual element inside the list, we

60:25

need to modify them through index.

60:27

Therefore, we must loop over the range

60:30

object.

60:32

Hey, isn't it bit verbose to write code

60:35

like this?

60:36

Yep, I should use the more compact

60:38

syntax of updating variable, writing

60:41

plus equal five instead.

60:45

Another application of range object is

60:48

that sometimes we want our program to

60:50

make decision based on the index of the

60:53

element rather than the value of the

60:55

element. Still using the salary list as

60:58

an example, but this time we want to

61:00

increase the salary of a few workers by

61:03

$10 because they're just so amazing.

61:07

Namely, there is another list which

61:09

stores the indices of those candidates

61:11

who we deem as amazing. For everyone

61:14

else, we still increase their money by

61:16

five.

61:18

Our program logic here is very

61:20

straightforward. We iterated over all

61:22

the indices with the help of if else, we

61:25

differentially increase the salary by

61:27

checking whether if the candidate is

61:28

amazing.

61:36

Loop variable I binds to zero and the

61:39

index zero is not inside amazing list.

61:42

So, our program jumps to the else part,

61:45

increase the salary by five.

61:49

I then binds to one. The index one

61:52

inside amazing list, true.

61:55

So, we increase the element by 10.

61:58

The same logic repeats all the way till

62:00

the end.

62:10

In general, as a Python programmer, it

62:12

is important to be absolutely fluent

62:14

with both technique. So, depending on

62:16

different coding task, we can always

62:18

pick the most optimal strategy to loop

62:20

over list.

62:25

Yet, sometimes our main focus does not

62:27

have to be a list, but rather a sequence

62:29

of number themselves. In particular,

62:32

when we're doing computation that

62:34

relates to math.

62:35

Have you ever seen a funny-looking thing

62:37

like this? An exclamation mark next to a

62:40

number.

62:41

It's called the factorial of that

62:43

number.

62:45

The factorial appears often in

62:46

probability, number theory, calculus,

62:49

and many other fields of mathematics,

62:51

playing important role in mysteriously

62:53

elegant equations.

62:56

Yet, its definition is very simple. The

62:59

factorial of a number n is defined as

63:01

the product of all the numbers from n to

63:04

one.

63:05

For example, 5! is 5 * 4 * 3 * 2 * 1.

63:11

If someone throws me a pen and paper and

63:14

ask me to calculate this expression,

63:16

this is what I would do.

63:17

Firstly, I know that multiplication is

63:19

commutative, so I can rearrange the

63:21

expression by reversing the numbers.

63:25

Then, I'll iteratively multiply the two

63:27

front numbers together. 1 * 2 is 2, 2 *

63:31

3 is 6, 6 * 4 is 24, 24 * 5 is 120. So,

63:37

5! is 120.

63:42

But, the process certainly gave me some

63:44

inspiration.

63:45

Those sequential numbers just look like

63:47

a ranged object.

63:48

The action of repeated multiplication

63:51

also rings a bell with the spirit of

63:52

loop.

63:54

So, let's write a program that can

63:56

compute the factorial of any positive

63:59

integer.

64:00

We initialize the variable P as 1

64:02

outside the loop. When the loop is

64:04

running, we iteratively multiply the

64:06

variable I into P.

64:19

The variable P basically serves as a

64:21

collector, storing the product of all

64:23

the natural number it had seen as a loop

64:26

marches forward.

64:35

You might wonder, why are we setting the

64:37

outer variable P to be 1 instead of 0?

64:40

Isn't that what we always do before?

64:43

The reason is because 0 multiplied by

64:45

anything is 0.

64:47

Suppose I accidentally initialize P = 0.

64:51

This is what's going to happen. P equals

64:53

to I * P, so P equals to 0 * 1, so P is

64:57

0.

64:58

P equals to 2 * 0, so P is still 0.

65:03

P equals to 3 * 0, so P is still 0.

65:07

As you see, the value of P is trapped at

65:09

0, never accumulating anything. This is

65:13

a problem.

65:15

Normally, when the purpose of the for

65:17

loop is to add bunch of numbers

65:19

together, the outer variable is

65:21

initialized to zero.

65:23

When the purpose of the loop is to

65:24

multiply bunch of numbers together, the

65:26

outer variable is initialized to one.

65:31

N is a variable, and I can initialize it

65:33

to a different value, such as 52.

65:36

Run this again.

65:37

The factorial of 52

65:40

Huh, this number is pretty big.

65:44

You know, the lesson so far today has

65:47

been pretty intense.

65:48

So, why don't we take a break together

65:50

by taking a detour on this 52 factorial?

65:54

This number is in fact so big that

65:56

people are making videos online

65:57

explaining how big the number is.

66:01

While I was watching them, I got a sense

66:03

that human beings are actually pretty

66:05

bad at comprehending big numbers.

66:07

52 factorial is a big number. The net

66:10

worth of Elon Musk is also a big number.

66:13

Currently, in 2022, Elon's net worth is

66:16

estimated to be around 200 billion

66:18

dollars.

66:20

I believe a few years later, that number

66:22

would increase to 800 billion dollars.

66:26

But, you know what's a number so much

66:28

and so much bigger than that? The number

66:30

of atoms on Earth.

66:33

Which is estimated to be 1.33 * 10 to

66:36

the power of 50.

66:39

All right. The next part might appear

66:41

weird to you, but imagine if every tiny

66:44

little single atom on Earth, each and

66:46

every one of them, transforms into their

66:48

own pile of 800 billion dollar cash. The

66:51

aggregation of total value here is

66:54

really immense.

66:56

And that equals to Elon money times num

66:59

atoms.

67:00

And this is truly a big number.

67:04

So, which number is bigger? 52 factorial

67:07

or 800 billion times the number of atoms

67:11

on Earth?

67:12

Personally, I think the latter number

67:14

must be bigger.

67:18

Oops, I'm wrong. 52 factorial is bigger.

67:22

Well, then what fraction does this big

67:24

number occupy in 52 factorial?

67:27

1.31 * 10 to the power of minus six.

67:31

That's a small portion. To visualize,

67:33

the yellow cube represents 800 billion

67:35

times the number of atom on Earth.

67:37

The larger green cube represents

67:40

52 factorial.

67:43

Wow, this 52 factorial is so big. In

67:46

what occasion does this even appear in a

67:48

human's life?

67:50

It's all the different unique ways you

67:51

can rearrange a poker deck.

67:55

All right, break is over. Let's come

67:56

back to Forloop.

67:58

Mushroom is taking a math class and she

68:00

got this answer for a question. This

68:03

entity may look unfamiliar to some

68:05

people. It's called the sigma notation.

68:07

It appears pretty often in math,

68:09

actually. Mushroom wants to find out the

68:11

numerical value of this expression.

68:14

Since Potato knows Python, she goes to

68:16

Potato for help.

68:19

However, Potato is scared anytime when a

68:21

Greek symbol appears in math. He doesn't

68:24

know whatever this thing is. So,

68:26

Mushroom explains.

68:28

The sigma notation is actually only

68:30

doing something very simple.

68:32

Consider all the natural numbers

68:34

starting at one ending at 10.

68:37

We pattern match this expression to them

68:40

one by one.

68:47

And then, we add them together.

68:50

Sigma notation is just a compact way of

68:53

describing summation.

68:55

Potato understands now.

68:57

But, wait a second. A sequence of

68:59

consecutive numbers adding a bunch of

69:02

numbers together both of which are just

69:05

screaming out use for loop.

69:08

I mean, one day in the future, whenever

69:10

you see a sigma notation in math, you're

69:13

just going to involuntarily ask yourself

69:15

it's just a for loop, right?

69:19

Potato picks up Python and passionately

69:22

programs.

69:27

And I will stop talking to let the

69:30

animation speak for itself.

70:06

Whenever we use a for loop, we can

70:08

literally put anything inside its

70:10

indented code block. Within loop, we can

70:13

print, we can do variable manipulation,

70:16

conditional statement, we really have

70:18

complete freedom as programmer.

70:20

But what if I put another for loop

70:23

inside a for loop, which results in a

70:25

nested for loop?

70:28

Loop inside loop. And this is when

70:30

things starts to get interesting. For

70:32

me, frankly, there's something

70:33

unsettling looking into a nested for

70:35

loop. What exactly happens? Most people

70:38

have this intuition about a nested

70:40

double for loop, saying, "Well, if a

70:43

single loop is all about one loop

70:46

variable hopping over each element of

70:48

its iterable,

70:50

then a double for loop must be about

70:52

Well, there are two different loop

70:54

variable,

70:55

then two different loop variable are

70:57

simultaneously running over two

70:59

iterable. And unfortunately, this

71:01

intuition about how double for loop

71:03

works is just incorrect.

71:07

So, what is the true behavior of a

71:09

double for loop?

71:11

Remember that there are two loop

71:12

variables, VL for the outer loop and VN

71:16

for the inner loop.

71:17

The VN needs to complete its entire trip

71:21

for VL to only advance by one step.

71:25

Or you can imagine this.

71:26

Every time when VL takes one step

71:28

forward, VN needs to complete its entire

71:32

loop.

71:33

VL takes another step forward, VN

71:36

completes another trip.

71:38

So, when the outer loop terminates, the

71:40

inner loop has been iterated over many,

71:42

many, many times.

71:44

At least for me, this behavior is

71:46

slightly unexpected. This is important.

71:49

Let's watch this again.

72:02

So, if we were to look at the output

72:05

generated by the print statement here,

72:07

it's going to look something like A1,

72:11

A2,

72:12

A3,

72:14

A4,

72:15

A5,

72:18

B1, B2, B3, B4, B5. You kind of get the

72:23

point.

72:24

You also notice the value of the outer

72:27

loop variable is persistent for the

72:30

entire duration of the inner loop. This

72:33

outer loop variable, which currently is

72:34

D, is used to concatenate with every

72:37

single inner loop element before it

72:40

expires and advance forward to become E.

72:43

Despite its complexity, nested for loop

72:46

is used inevitably in programming, such

72:49

as a matrix multiplication

72:51

and dynamic programming.

72:53

But today, let's just focus on a very

72:55

simple application.

72:57

Suppose I'm coding a poker game. So, the

73:00

first thing I need to do is to create a

73:01

deck of 52 cards,

73:03

which is conveniently represented as a

73:05

Python list.

73:07

I'll just manually add each card in

73:09

there one by one. I append two of

73:11

hearts, two of diamonds, clubs, and

73:13

spades.

73:14

And after doing this 52 times

73:16

diligently, I'm done with my deck of

73:18

cards. But, this just doesn't feel like

73:21

the most efficient way of doing things.

73:24

I could make the observation that a

73:26

poker deck only has 13 different rank

73:28

and four different suits.

73:30

The formation of a deck is just each

73:32

rank take four different version of

73:34

suit.

73:35

It's just combination.

73:38

And this looks suspiciously like a

73:40

double for loop.

73:42

Therefore, I can write my Python code as

73:45

I have my outer loop iterating through

73:47

all ranks.

73:49

The inner loop iterating over each suit.

73:52

And the card is simply the concatenation

73:54

of a suit and rank.

73:56

And I append the card to my cards.

74:00

And this double for loop will get my

74:01

deck of 52 cards.

74:07

At this point, it's totally okay to feel

74:10

nested loop is kind of hard.

74:12

Absolutely. Especially if it's your

74:14

first time seeing this.

74:16

Compared to a single for loop, the

74:17

complexity of double for loop is in fact

74:20

not double, but square.

74:24

Unfortunately, things can even get

74:26

harder from here.

74:28

Let's take a moment to compare the two

74:30

different program here.

74:31

Can you spot out why the code on the

74:33

right is much more difficult to

74:35

understand?

74:36

Feel free to pause and ponder.

74:42

All right.

74:43

If we look at the left program, the

74:45

inner loop always loops over from the

74:48

range 0 to 5, independent of the outer

74:51

loop.

74:52

On the contrary, the right one, the

74:55

inner loop is iterating over range 0 to

74:58

I.

74:59

But, what is I?

75:01

I is the outer loop variable, which

75:04

means it changes through the execution

75:06

of the program.

75:08

The iterable of the inner loop depends

75:10

on the outer loop. There is a

75:12

fundamental dependency between the two

75:15

loops.

75:16

So, what does that look like?

75:19

When the outer loop just begin, the loop

75:21

variable I binds to 5. According to our

75:24

program, the inner loop needs to take a

75:26

trip from 0 to 4.

75:29

As the inner loop terminates, the outer

75:31

loop take one step forward. I is now 6,

75:35

which means the inner loop needs to

75:36

iterate from 0 to 5, which is one more

75:39

than its previous run.

75:40

I binds to 7, the inner loop goes from 0

75:44

to 6.

75:45

I binds to 8, the inner loop needs to go

75:48

from 0 to 7.

75:50

I binds to 9, the inner loop needs to go

75:53

from 0 to 8. So, you already see the

75:56

pattern. As the program execute, the

75:59

extent in which the inner loop needs to

76:00

iterate also increase. The behavior of

76:04

the inner loop, how much work it does,

76:07

is depend on the outer loop.

76:11

Why would a programmer ever use a nested

76:13

loop that has dependency?

76:16

Well, remember from last chapter, we

76:18

learned about factorial.

76:20

If we want to compute the factorial of

76:22

integer n, we use a for loop from 1 to

76:25

n, iteratively multiplying each number,

76:28

and accumulate into p.

76:32

However, what happen if someone throws

76:34

me list of integer, and ask me to

76:36

compute each one's factorial? What

76:38

should I do?

76:40

Let's look at this again. This block of

76:42

code computes the factorial of n, and n

76:45

is a variable. I can change n to 11 and

76:48

see that the factorial of 11 is a big

76:50

number.

76:51

So, why can't I change n into a loop

76:55

variable iterating over number list? And

76:58

it would just migrate this entire code

77:01

block inside, of course, indented.

77:05

Notice we have a nested loop with

77:07

dependency of the inner loop range from

77:09

1 to n + 1.

77:11

The mission of the outer loop is to

77:13

iterate all integers from this given

77:15

list. The mission of the inner loop is

77:18

compute the factorial of that

77:19

corresponding n.

77:21

Execute.

77:22

Great.

77:25

There is one detail to point out. Notice

77:28

on line two, p equal to 1 is in between

77:31

the outer loop and the inner loop. This

77:33

means that every time when the variable

77:35

n take one step forward, rather than

77:37

launching the inner loop immediately,

77:39

the first thing it does is to reset p

77:42

back to 1, then follows the entire inner

77:44

loop. This reset is critically important

77:48

because when the inner loop is

77:49

calculating the factorial, the value p

77:52

gets pretty big.

77:54

As the outer loop take one step forward,

77:56

we need to reset p back to 1, so the

77:59

residual from the previous inner loop

78:01

does not linger over.

78:05

Loop is the most important concept in

78:07

the basics of programming, which is why

78:09

we spent three chapter on this topic. We

78:11

start learning about loop from a visual

78:13

approach. We see with our eye that the

78:15

loop is really running. In part two, we

78:18

learn about how to loop with the range.

78:20

And today, we saw the unexpected

78:22

complexity of a nested for loop.

78:25

In terms of big picture of essence of

78:26

Python, we have already added these

78:29

items to our toolbox. Variable

78:31

manipulation, which is a unit of

78:33

compute, conditional statement, decision

78:35

making, Python list, data structure, for

78:39

loop, automation of logic.

78:41

These combined may only occupy 20% of

78:44

Python's programming feature and syntax,

78:47

but the core concept are definitely

78:48

relevant in at least 80% of any

78:51

programming thinking.

78:52

An interesting note aside, when Vitalik

78:55

was developing the next generation

78:56

blockchain, Ethereum, he was especially

78:59

aware about the feature of loop. He

79:01

realized that Bitcoin's foundational

79:02

limitation is that it doesn't allow

79:04

loop. So, he added a loop in Ethereum,

79:07

which enabled it to become versatile

79:08

platform for developer to make

79:10

interesting application.

79:16

When people say function, we think about

79:19

the X and Y axis. This is a linear

79:22

function. This is a quadratic function.

79:25

Our impression about function is often a

79:27

static image we see in our math

79:28

textbook. However, this is actually

79:31

quite misleading because the essence of

79:33

function is not static. It's dynamic.

79:37

Function is all about the action of

79:39

transforming input into output.

79:44

For example, this function here computes

79:46

the squared value of any number.

79:49

Five enters the function. Five squared

79:52

is 25.

79:53

And 25 is the output.

79:56

And this function here is capable of

79:58

interleaving two input string. A A A A,

80:02

B B B B are the inputs. The function

80:04

inter- leaves them

80:06

and outputs the longer string.

80:08

What you saw just now very much

80:10

resembles the essence of a Python

80:12

function. There is an input. The

80:15

function does something to the input and

80:17

returns the output back to you.

80:20

This is a good mental picture to have

80:21

before the lesson begins.

80:23

In Python, function is a great way for

80:26

organizing logic and prevents you from

80:28

writing repetitive code. To motivate

80:30

this, let's see an example.

80:32

Recall in chapter five, potato mastered

80:35

the use of for loop, and now he's a

80:37

senior engineer at YouTube.

80:41

But, what is he doing today? You can

80:43

pause the video to take a look.

80:48

Seems like potato is writing a greeting

80:50

message to members in the gold, silver,

80:53

and bronze class.

80:57

If today is a member's birthday, he

80:59

writes, "Happy birthday." Plus the

81:01

person's name.

81:02

Else, simply greet with, "Hey."

81:05

Lastly, the message is printed with the

81:07

person's class tier.

81:11

However, if you were to notice, these

81:14

three blocks of code are identical. This

81:16

is very repetitive, and this is not good

81:19

code.

81:21

Really, in those three places, potato is

81:23

seeking for the same functionality.

81:26

Given person's name and his birthday as

81:28

input, we want to get its corresponding

81:30

message as the output. This is a great

81:33

place we should use a function.

81:41

Finally, how do you make a function?

81:43

We use the def keyword, short for

81:45

define. Follow that, we give the

81:48

function a name, greet, and then, within

81:51

the parentheses, we specify what are the

81:54

inputs to the function, which is the

81:56

name and birthday today.

81:58

The professional terminology is that

82:00

they are the parameters of the function.

82:03

Now, we can write code that performs

82:05

action to the parameters.

82:07

Notice indentation here, which is saying

82:09

everything within the indentation belong

82:12

to the function greet.

82:14

The return keyword specify the output,

82:16

which is the conditional message.

82:19

I want to take a moment to emphasize

82:20

that the return statement here is very

82:22

important. If you forget to write a

82:24

return statement, you can imagine that

82:26

your desired output gets stuck inside a

82:28

function with nothing visible from the

82:31

outside.

82:33

This entire thing is a function

82:35

definition. We define the input, the

82:37

action, the output. But when a function

82:40

is defined, nothing happens yet. It's

82:43

sort of just sleeping there, but ready

82:45

to be summoned.

82:46

It is not until the line you are calling

82:48

the function with actual input. Notice

82:50

the def keyword is not here, and the

82:52

parentheses contains real string and

82:54

boolean.

82:55

This is when you want your function to

82:57

do its magic.

82:59

The greet function transform the input

83:01

into the output.

83:04

Question. What exactly is this parameter

83:06

thing? Are they like variable?

83:09

They're a little unintuitive to look at.

83:11

Good question.

83:12

They're not exactly a variable.

83:14

If you think about it, when we define a

83:16

function, we never know what will be the

83:18

actual input. They could be anything.

83:22

Therefore, the parameter serves as a

83:24

placeholder variable, and we write code

83:26

in respect to those placeholder.

83:29

Only when we're calling the function,

83:31

the placeholder variable manifest into

83:33

the value of the real input.

83:36

Let's look at the execution of function

83:38

in detail.

83:39

Once again, when the function is

83:40

defined, nothing happens.

83:44

At line number eight, function greet is

83:46

called with tangible input name for Erin

83:49

and a false for birthday today.

83:54

The two placeholder now manifest into

83:57

Erin and false.

83:58

And then the original code for the

84:00

function executes.

84:03

And the value message is returned

84:05

and bind it to the variable M.

84:11

You might have noticed something. These

84:13

two assignment statement was not part of

84:15

the code we wrote.

84:17

But I intentionally put them here

84:18

because this is a correct mental picture

84:20

I want you to have.

84:22

When placeholder parameter finally takes

84:24

on the value of real input,

84:26

it is basically an implicit assignment

84:28

statement as they are top.

84:31

Now, we can go back and improve potato's

84:33

code.

84:34

Message now becomes the return value of

84:36

a function.

84:38

This code is much better now.

84:41

Let's look at a few more examples of

84:42

functions together, and you will see

84:45

just how versatile function design can

84:47

be.

84:48

You can make a function that has one

84:49

parameter,

84:52

or three parameters,

84:54

or 10 parameters,

84:59

or even zero parameter.

85:01

Notice when you're calling a function

85:02

that has zero parameter, you still need

85:05

to pass in the parentheses,

85:06

but just with nothing inside.

85:09

You can almost sort of think the

85:10

parentheses as something that activates

85:12

the function.

85:15

What code can I write inside a function?

85:18

Literally anything.

85:20

You can write a for loop. This function

85:21

computes a factorial. You can write

85:24

conditional statement. This function

85:26

converts temperature between Celsius and

85:28

Fahrenheit.

85:29

Your function can even use other

85:30

function, which is defined previously.

85:33

This check password strength function

85:35

uses two other function for its internal

85:37

logic.

85:39

In terms of function design, the only

85:41

limit is your imagination.

85:47

Many YouTube video out there often like

85:49

to motivate Python function as a way to

85:52

package print statement together,

85:54

rather than looking at the essence of

85:55

function, which is all about input and

85:58

output.

85:59

This type of teaching leads to a common

86:01

confusion, which is what is difference

86:03

between print versus return inside a

86:05

function.

86:08

Let's look at the two function here.

86:12

If I execute the function on the left,

86:14

it prints hi Bobo.

86:17

If I execute the function on the right,

86:19

it returns Hi Bobo and then I print it.

86:22

On both screen, I see Hi Bobo. So,

86:25

there's no difference, right?

86:28

Hm, not quite.

86:31

Notice the function on the left. It

86:32

doesn't have a return statement. So, the

86:35

function has no output.

86:37

What happens here?

86:38

When a function doesn't return anything,

86:40

Python secretly make the function return

86:43

a none value

86:44

to indicate the absence of anything.

86:49

So, if I bind the return value of the

86:52

function to M and I print M,

86:55

ah, what I get is a none here.

86:58

If I want to print Hi Bobo five times, I

87:00

cannot. I get none five times because

87:03

the variable M is a phony and the

87:05

function didn't return me anything at

87:07

all.

87:09

Whereas I could do with the function on

87:10

the right because it return.

87:13

Moral of the lesson here, don't fool

87:15

yourself by printing inside a function

87:17

and think that's a return value.

87:19

Before we wrap up a session today, there

87:21

is one more critical concept you need to

87:23

take away.

87:24

The return statement Python immediately

87:26

terminates the execution of function.

87:29

When the return statement is triggered,

87:31

the function stops in a non-negotiable

87:33

way.

87:34

My question for you, take a moment to

87:36

pause and ponder.

87:38

If I'm calling the boot computer

87:39

function on the input false,

87:42

would I see these lines of code being

87:44

printed?

87:50

The answer is no. I would not see them

87:52

because my input for has OS installed is

87:55

false.

87:56

At line number five, the if statement

87:58

evaluates not false, so true.

88:01

Then it executes the return zero, which

88:04

immediately terminates the function.

88:06

Everything afterwards is ignored.

88:09

By the way, I also just learned that you

88:11

could actually put emoji in Python

88:12

string.

88:14

Question. If you have a return statement

88:17

inside a for loop, can the return

88:19

statement even stop the for loop before

88:21

its completion?

88:22

Absolutely, it can.

88:25

Let's take a quick detour into prime

88:27

number. Quick review. A prime number is

88:30

a natural number strictly greater than

88:31

one that is not perfectly divisible by

88:34

any number smaller than itself other

88:36

than one.

88:38

For example, seven is a prime number

88:41

because when seven is divided by any

88:42

smaller number,

88:44

the remainder is always non-zero.

88:48

Nine on the other hand is not a prime

88:50

number

88:52

because 9 / 3 is 3

88:54

with a remainder of zero.

88:57

One thing I can tell you is that prime

88:59

number holds a special place in the

89:01

heart of mathematician and computer

89:03

scientist.

89:04

Prime numbers are the backbone for

89:05

internet security. Without prime, your

89:08

password, bank info, messages would all

89:10

just be public.

89:12

And as programmer can easily write a

89:14

function to check if a number is prime

89:16

or not.

89:17

The is_prime function uses for loop to

89:19

iteratively look at all the natural

89:21

numbers smaller than n, but excluding

89:23

one,

89:24

and it compute the remainder. If the

89:26

remainder is zero, then immediately we

89:28

know that it's not a prime number.

89:30

Only if all iteration of the loop has a

89:32

non-zero remainder, then n is a prime.

89:36

If what I said is a little confusing,

89:38

let's see what happens when I call the

89:39

function on the number 25.

89:43

So, firstly, n binds to 25. 25 is bigger

89:47

than one, so it skips here.

89:49

Now, we're running a for loop from 2 to

89:51

24.

89:55

We check the remainder of 25 / 2.

89:58

Not zero. So, we do not enter the return

90:01

statement.

90:02

We do the same for three.

90:05

We do the same for four.

90:08

Now, the remainder of 25 / 5 is zero and

90:12

the return statement is triggered.

90:15

This function immediately stop and

90:16

return false. 25 is not a prime number.

90:20

Notice how all the latter parts are just

90:22

ignored.

90:24

The loop didn't even get to them.

90:26

And finally, the return value false bind

90:29

with the variable result.

90:33

Well, since I just defined the is prime

90:35

function, I get to use it. Let's append

90:38

all the number between 1 and 1,000 to a

90:40

list.

90:41

Let's see who are these guys.

90:46

And how many of you are here?

90:49

What about between 1 and 10,000?

90:53

Hm, very cool.

90:56

Function, input, output. I said them a

90:59

million times and I bet you're tired of

91:00

it. But that's the essence of function

91:03

and I hope you can internalize that

91:05

idea.

91:05

Programming and computer science

91:07

ultimately is about abstraction

91:09

and abstractly speaking, many things are

91:12

functioning our life.

91:13

We know that this is a function,

91:15

but an ATM is also a function. The input

91:18

is your card and PIN number. The output

91:21

is the money.

91:23

Even this is a function. The input is a

91:26

character. The function miniaturize the

91:28

input and a smaller character is the

91:30

output.

91:59

You might have noticed something

92:01

interesting. Every time when a function

92:03

call happens, it creates a sandbox like

92:06

this.

92:06

All variable assignments, program logic

92:09

happens within.

92:10

When a function returns, this sandbox

92:13

vanishes.

92:14

You might wonder, what is so important

92:16

about this mental picture of a sandbox?

92:19

Well, let me show you.

92:21

We have variable X equal to 1.

92:23

Then we create a function.

92:25

But within a function, we have another

92:27

variable of the exact same name. X equal

92:30

to 25.

92:32

Then I do Y equal X, and then return Y.

92:35

So, the existential question here is

92:37

that when I assign Y equal to X, which X

92:40

am I looking at?

92:41

Is it the X outside the function, or the

92:44

X inside the function? Well, what's your

92:46

guess?

92:50

Let's execute the program and see what

92:52

happens.

92:59

Ooh.

93:00

It seems like it's 25.

93:03

So, the X inside the function.

93:06

During the function execution process,

93:08

we always prefer to look at the variable

93:10

within the sandbox.

93:13

Let me ask a follow-up question.

93:15

Suppose I change the code, and I remove

93:17

this line. So, there is no X within a

93:19

function definition.

93:21

If I still do Y equal to X, can Y find X

93:25

from line number one, or this program

93:27

would lead to an error?

93:34

Let's find out.

93:37

Y equal to X, but there's no X. So, the

93:41

function looks outside, and find X in

93:44

the global scope, and binds Y equal to

93:47

1. Seems like the program can indeed

93:50

find variable outside the function

93:51

definition.

93:53

These two examples just now highlights

93:55

an important message. In function

93:57

execution, we always prioritize variable

94:00

lookup in the local scope. Only if not

94:03

found, then we look into the global

94:05

scope.

94:06

The term local scope is a fancy but

94:08

professional way of saying everything

94:10

within the sandbox. And global scope is

94:13

everything outside.

94:15

Wait a second. Why would anyone write

94:18

code like this? This feels intentionally

94:20

confusing.

94:21

Why do you have to create a local

94:23

variable with the same name as a global

94:24

variable?

94:25

Just change it to a unique name and you

94:28

can avoid all this confusion.

94:30

Well,

94:30

I totally agree.

94:32

Almost no one at a tech company will

94:33

write code like this.

94:35

But distinguishing between local scope

94:37

and global scope is important. So, bear

94:40

with me here.

94:43

Local scope has access to global scope,

94:45

but the other way around is not true.

94:48

Once again, let me modify the code.

94:50

On line number nine, rather than print

94:52

result, I print K, which is defined only

94:54

within a function.

94:56

What happens?

95:02

When the program tries to print K,

95:04

but there is no K anywhere to be seen in

95:06

the global scope.

95:08

Well, there was a K when the function

95:10

was executing,

95:11

but it vanished alongside with the

95:13

sandbox.

95:14

So, this program actually give you an

95:16

error.

95:18

Let's talk about interesting topic

95:20

called function composition.

95:22

I have two function here. Function F

95:24

takes input R and compute pi r squared.

95:27

You might notice that's the formula for

95:29

area of a circle.

95:31

Function G simply multiply four for its

95:33

input.

95:34

What's so special about the four here?

95:37

It's because the surface area of a

95:38

sphere is actually four times the area

95:41

of a circle projection. So, if someone

95:43

asked me, what is the surface area of a

95:45

sphere that has radius five? I can first

95:48

compute the area of a circle whose

95:49

radius is five and store into variable

95:52

A. Then the function G multiply A by 4.

95:55

This gives me the surface area of that

95:57

sphere.

95:58

This is very good. But you might wonder,

96:00

since A is just a return value of of f

96:03

of phi,

96:04

why can't we just pass f of phi directly

96:06

as an input for the function G? And this

96:09

would actually make our code more

96:10

concise. Yes, you can.

96:13

But why is that?

96:14

In Python function call, you always

96:16

evaluate the input before jumping to the

96:18

function execution.

96:20

Evaluate is kind of my fancy way of

96:22

saying, if the input in my function is

96:24

actually another function call, I got to

96:27

figure out what is return value of the

96:28

inner function first.

96:31

This is what it looks like.

96:32

We first evaluate the function f of phi.

96:37

It returns 78.5.

96:39

And that becomes the input to the outer

96:41

function G.

96:42

And then the function call for G

96:44

happens.

96:48

I can even exaggerate this idea by

96:50

showing you a triple nested function

96:51

call.

96:52

But you already know what happens here.

96:54

We're calling function H.

96:56

But what is the input?

96:57

It's clearly not a number, but rather

96:59

another function call. So I need to

97:01

evaluate its input G of f of phi.

97:04

In order to do that, I need to evaluate

97:06

function G.

97:07

But I need to evaluate f of phi first.

97:10

You see, the process is almost like me

97:12

peeling an onion until we get to a

97:13

function call that's not nested. And

97:16

then it works its way backwards. When we

97:18

chain multiple functions together like

97:20

this, it's called composition.

97:22

And the idea of function composition

97:24

actually originates from math, not

97:25

programming.

97:27

For many difficult concepts in math, I

97:29

find myself only to truly understand

97:31

them after I learned programming. Where

97:33

I try to explain mathematical concepts

97:36

through the lens of Python.

97:37

In high school, the math class start

97:39

teaching you about function composition.

97:41

You probably see something like this.

97:42

And you already know, the next thing the

97:44

question is going I'm going you is, what

97:46

is f of g of 20?

97:48

After learning programming, this

97:50

question is almost trivial. I first

97:52

define f like the way it's written in

97:54

the question, and then I define g,

97:57

and then I define f of g,

97:59

and simply I call f of g on 20.

98:01

That's the answer.

98:03

Programming in essence is mathematics in

98:06

action. If this feels déjà vu to you,

98:08

you're probably thinking about chapter

98:10

6, where we said the scary sigma

98:12

notation is really just a for loop in

98:14

Python.

98:19

In the last two videos, I've been using

98:20

the word inputs a lot when describing

98:22

the thing that enters a function. I

98:24

didn't want to detour the lesson by

98:26

spending too much attention on

98:27

terminology. The more professional

98:29

terminology for input is actually

98:31

arguments for the function. Very

98:33

interesting choice of word right there.

98:35

Cool. Today's lesson is a bit tedious. I

98:38

want to end it with a quote from a

98:39

legendary programmer called Terry Davis.

98:42

Idiots admire complexity. Genius admire

98:44

simplicity. Terry is a bit of a

98:47

controversial figure, but I do agree

98:49

with this sentence here.

98:50

Programming is not about writing fancy

98:52

and convoluted code to impress your

98:54

peers. Programming is about writing the

98:56

simplest and readable code, so everyone

98:58

can tackle the same underlying problem

99:00

together. Let me give you an example. If

99:02

I were to look at this code, I won't be

99:04

able to figure out what's going on. I

99:06

see there's a for loop, but there's so

99:09

many things happening within the for

99:10

loop, which makes it difficult for my

99:12

brain to render what's the intention

99:14

behind. But the very identical logic

99:17

when written differently can be

99:18

instantly readable.

99:20

Look at the improved version here.

99:22

You see the programmer first break down

99:23

the big problem into multiple small

99:25

function definition,

99:26

and simply by reading the name of

99:28

function, you can gauge into its

99:30

underlying purpose.

99:31

And there's documentation. The goal is

99:34

to buy stocks based on Google search

99:36

trend and sentiment analysis based on

99:37

news article.

99:39

We have a list of potential candidates.

99:41

For each candidate, we check its Google

99:43

search trend. If there is momentum in

99:45

search volume for last 3 hours, it

99:48

passes the first round check as a trendy

99:49

stock.

99:50

Then, for the surviving trendy stock, we

99:53

fetch all the news from today about that

99:55

stock and ask GPT to rate a score from 0

99:57

to 10. If the score is more than 7, then

100:00

we buy it. And this is good code. This

100:03

is what peak programming looks like. It

100:05

pipeline multiple functions together

100:07

rather than trying to do everything in

100:09

one place. It feels like you're no

100:11

longer reading computer code, but you're

100:13

reading human language.

100:18

Today, we talk about a slightly advanced

100:20

topic, value versus reference.

100:23

A quick review. When we do variable

100:25

assignment for number and string, we

100:27

assign by making a copy of the value.

100:30

This is a correct mental picture.

100:32

Variable B takes on the value of 7, but

100:35

a common mistake is this one. In which

100:37

people imagining the assignment makes

100:39

variable B becoming variable A itself.

100:42

This is the incorrect mental picture to

100:44

have. With this understanding, we know

100:47

that if later on I reassign variable B

100:49

to something else, variable A is still

100:52

untouched. If I print A, it still prints

100:54

7.

100:55

Cool. So far, so good. If the variable

100:58

is number or string, we know what

100:59

happens. But, what about Python list?

101:02

Previously, I foreshadowed that when I

101:04

create a list, my variable is a

101:06

reference towards a list. Rather than my

101:09

variable containing a list, I never

101:11

explained why. So, what is your mental

101:14

picture when I do list assignment? Is it

101:16

this one? Do I create a reference to the

101:18

same list?

101:20

Or this one? I make a copy of the Python

101:23

list.

101:25

And surprisingly, we don't make a copy.

101:27

The new variable would have the same

101:29

reference to the original list. And this

101:32

has a profound implication.

101:34

Let's say if I change the second element

101:36

of list B,

101:37

I will first follow the reference

101:38

pointed by list B, and then modify the

101:41

second element. But you see, since the

101:43

list A also reference towards the same

101:45

data, my modification on B has

101:48

unintentionally affected A. If I print

101:50

A, it's no longer 1 2 3.

101:53

You see, assignment of list very much

101:55

forms a stark contrast with number and

101:57

string.

101:58

For number and string, you assign a new

102:00

variable by making a copy of the value.

102:03

Changing the new variable has absolutely

102:05

no impact on the original one. For list,

102:08

you make assignment by reference.

102:10

Changing the new variable induce

102:11

mutation on the original one.

102:15

Next, let's up notch the difficulty by

102:17

bringing function call into play. But

102:19

don't worry. I promise you that nothing

102:21

had fundamentally changed from just now.

102:24

So, what I have here is that I have a

102:26

function f of x.

102:28

The function increased the value of its

102:29

input by one,

102:31

and doesn't have return statement.

102:33

And then, I create a variable with k

102:35

equal to 10.

102:36

I call the function f on k.

102:38

So, if I print k, am I going to see k

102:40

becoming 11?

102:42

But first, let me ask you, what's your

102:44

mental model?

102:45

When I pass the variable k as input to

102:47

function f,

102:49

are you imagining something like this?

102:51

The value of k, which is integer 10,

102:53

enters the function.

102:56

Or is your mental model the variable k

102:58

itself entering the function?

103:01

The quick answer, not surprisingly,

103:03

is the former.

103:05

Just like a variable assignment, for

103:06

string and number, it's the value that

103:09

gets moved. Let's execute the code to

103:11

confirm.

103:13

Since the input is really the value of

103:15

10 entering the function, but not the

103:17

variable k, if I increase 10 to 11, that

103:20

has no business to do with the original

103:22

k.

103:23

After the function call, if I print k, I

103:25

still get 10.

103:27

What about if a variable is a list, and

103:29

we're passing it to a function? Which

103:31

one would it be?

103:32

Are you passing the reference to the

103:34

list to the function?

103:36

Or are you making a copy of the list?

103:39

You guessed it. We're passing the

103:41

reference because the variable is a

103:43

list. Let's see what happens with the

103:44

code here.

103:49

The function's input has the same

103:50

reference to the list V in the global

103:52

frame.

103:53

The function modify element zero to be

103:55

99.

103:57

And then it append a new element.

103:59

After the function call terminates, the

104:01

original list V is no longer the same.

104:06

At this point, the elephant in the room

104:08

is why.

104:09

Why do we have this complex rule and the

104:11

intricate difference between value and

104:13

reference?

104:14

Why can't we always just make a copy all

104:16

the time? So, we never need to worry

104:18

about reference.

104:20

And that's a wonderful question.

104:22

I'll first try to explain with analogy.

104:25

And then a more involved second

104:27

explanation from a computer hardware

104:28

perspective.

104:31

Suppose you read an interesting article

104:33

on your phone. And you want to share

104:35

with your friend. You have two options.

104:37

One, you type every single word verbatim

104:40

as a text message.

104:44

Or two. You can just share the link to

104:46

the article.

104:48

Well, preferably we would do the latter.

104:50

We don't want to spend time typing down

104:51

the text. Because the article is really

104:53

long. We just want to swiftly send the

104:55

link. And we know that our friend just

104:58

need to click open the link. The link is

105:00

just like a reference in Python. A

105:03

reference is lightweight. And passing

105:05

them is easy and fast.

105:07

Most Python lists in real programming

105:08

setting, they're very, very long.

105:10

Containing millions and billions of

105:12

elements.

105:13

We can't afford having computer making

105:15

copies of so many elements. Because

105:17

making copies data actually take time.

105:20

Now, let's dive into the second

105:22

explanation from a computer architecture

105:24

perspective.

105:25

Why does Python and many other language

105:27

use a reference?

105:28

Inside your computer, we have two key

105:30

players,

105:31

the CPU

105:33

and the memory.

105:34

The dance between them is what make your

105:36

code actually run.

105:38

Down here, we have the heap memory. This

105:41

is where large data lives, like Python

105:43

list.

105:43

For example, a list that contains the

105:46

entire book of Harry Potter sits right

105:48

here.

105:50

And near the top, we have the stack

105:52

memory, where function do their magic.

105:55

When a function runs, it needs

105:57

information about its input within the

105:59

stack memory. Now, we could copy the

106:02

entire list from the heap into the

106:03

stack. But look at this. It's slow, it

106:06

take extra space, and worst of all,

106:08

we're duplicating data we don't even

106:10

need to change.

106:12

Instead, we could do something smarter,

106:15

which is put a reference in the stack, a

106:17

tiny pointer, like a sticky note saying,

106:19

"Hey, look down there."

106:22

The CPU then follows the reference to

106:24

the heap, grabs the actual data, and get

106:27

to work.

106:28

Cool. Hopefully, you're starting to see

106:30

why references matter so much in

106:32

programming.

106:33

So for now, here's a simple rule you can

106:35

hold on to.

106:36

Lightweight data types, like numbers and

106:38

string, are passing by value.

106:41

But heavyweight types, like list,

106:43

dictionary, or class objects, are passed

106:45

by reference.

106:47

It's not a hard rule in every language,

106:48

but in Python, this general intuition

106:50

will take you pretty far.

106:54

Python dictionary, perhaps one of the

106:57

most useful data structure, in my

106:58

opinion.

107:00

Previously in chapter four, we learned

107:01

Python list, which can store a

107:03

collection of many arbitrary data. List

107:06

is also versatile for its operation. We

107:08

can easily access,

107:10

modify, add,

107:13

remove its element.

107:15

And most importantly, this is an

107:16

iterable, which allows us to run a for

107:19

loop. If Python list is so awesome, why

107:22

do we need dictionary?

107:25

A dictionary is all about relationship

107:28

between piece of data. And it turns out

107:30

we really care about those

107:31

relationships. Think about it. If you're

107:33

a football analyst, you don't just care

107:35

about how many goals Messi or Ronaldo

107:37

score in total. You care about how many

107:39

goals they score in a specific year. For

107:42

example, in 2015, how many goals Messi

107:45

score?

107:47

If you're a software engineer at Uber

107:48

Eats, you care about the name of a dish

107:51

and its corresponding price. If someone

107:54

order a pizza, how much does it cost?

107:57

If you manage inventory at Costco, you

108:00

probably want a data structure that

108:01

track the name of item and the quantity

108:04

left. How many dried mango we have?

108:07

Should we restock?

108:09

In all these cases, you're mapping one

108:11

piece of information to another. You're

108:14

saying, given this, tell me that.

108:18

This is exactly what Python dictionary

108:20

do. You provide what's called a key to a

108:23

dictionary. The dictionary finds the key

108:25

and it gives you back the corresponding

108:27

value.

108:29

And the beauty is that the key is

108:31

meaningful. The key is readable.

108:34

Compare that to a list, where you're

108:36

stuck with using the index to access the

108:38

element. The index has to be a number.

108:41

It does its job, but not as expressive.

108:45

Potato is now a software engineer at

108:47

McDonald. Today he's working on digital

108:50

menu. Let's help him out.

108:53

Potato wants to use the Python

108:54

dictionary to store the meals and its

108:56

price. So, he can easily look up the

108:59

price for particular meal. In this case,

109:02

the key is the name of the meal, the

109:04

value is the price.

109:07

To create a dictionary, we use the curly

109:09

bracket on our keyboard, not the square

109:11

bracket, because square bracket is

109:13

already used for Python list. Dictionary

109:16

fundamentally just store a collection of

109:18

many key-value pair. Let's first see how

109:20

we can create one key-value pair.

109:23

We write

109:24

the key,

109:25

colon,

109:27

and then its corresponding value, and

109:29

finish it off with a comma.

109:31

Now, we can use Big Mac to access its

109:33

corresponding price.

109:35

Next, we just need to apply the same

109:36

syntax for other pair.

109:39

Execute.

109:40

Here is our dictionary. I want to make a

109:42

remark that you can also just create an

109:44

entire dictionary on the same line like

109:46

this. Either way works. Your pick.

109:49

Next, we're going to learn about the

109:51

four primary operation for dictionary,

109:53

which are still access, add, modify,

109:57

remove.

110:01

A customer wants to buy a Big Mac, but

110:03

how much does a Big Mac cost? The syntax

110:06

for accessing the value is as follows.

110:09

We put the name of the dictionary, menu,

110:11

and square bracket.

110:13

Within the square bracket, the string

110:15

Big Mac.

110:16

Doing this, the variable P will bind to

110:18

the value of 5.99.

110:21

The key has to match precisely. One of

110:24

the most common bug is people

110:25

misspelling the key.

110:27

One interesting thing you might notice,

110:29

when we access the value, we're using

110:31

the square bracket, despite a dictionary

110:33

was created with a curly bracket. When I

110:35

learned Python, I also find this

110:37

unintuitive, but this is just how

110:39

Python's creator, Guido van Rossum, made

110:41

dictionary. We will just have to follow

110:43

his rule.

110:46

Once in a while, seasonal special item

110:48

ushers in. The Shamrock is a minty

110:50

flavor drink only offered around St.

110:52

Patrick's Day. Let's add it to our

110:54

dictionary menu. The syntax is on the

110:57

left-hand side of equal sign, we have

110:59

the dictionary name, menu, square

111:01

bracket, the key, Shamrock,

111:03

equal to its new value, 3.89.

111:07

That's it.

111:08

Here it is.

111:11

Next up, we have modification of

111:13

existing key value pair.

111:15

Due to inflation, McDonald has decided

111:18

to change the price of its popular item

111:20

Big Mac to $10 and double the price of

111:23

french fries. On line number 11, we

111:25

write menu square bracket Big Mac equal

111:29

to 10. This update Big Mac to $10.

111:34

But for french fries, we're doubling its

111:35

price, so it depends on the current

111:38

price.

111:39

Menu of french fries is equal to the

111:42

current menu of french fries times two.

111:48

You see, the syntax for modification is

111:50

identical to addition. If you give the

111:53

dictionary an existing key, it modify

111:55

its value within.

111:57

If you give the dictionary a new key,

111:59

then it adds the key value pair.

112:02

As Saint Patrick's Day pass by, seasonal

112:04

offering stops. It's time to remove

112:07

Shamrock from the dictionary, oh, I mean

112:09

menu. The syntax is menu.pop

112:13

parentheses the key you want to remove,

112:16

which is the string Shamrock in our

112:17

case.

112:19

Now, the Shamrock key value pair vanish

112:21

from the menu.

112:24

Dictionary is versatile.

112:26

I can create a dictionary, the key is

112:28

number and the value is string.

112:31

Vice versa, the key can be string and

112:34

the value is number.

112:36

I can also create a dictionary, the key

112:38

is string and the value is a Python

112:40

list.

112:43

The value of dictionary can even be

112:44

another dictionary.

112:46

This dictionary maps the name of

112:48

restaurant to its menu, which in turn is

112:51

another dictionary.

112:54

Let me show you how I can access a value

112:56

from something like this.

112:57

I do restaurant to menu with a key

112:59

Chick-fil-A

113:01

and its value is this inner dictionary

113:03

here.

113:03

Immediately after, I do another value

113:06

access with a key of waffle fries to

113:08

retrieve its price here. Variable P will

113:11

bind to 2.49. You almost have

113:14

unconstrained freedom with the creation

113:16

of dictionary. Yet, there's one

113:18

restriction. The keys of a dictionary

113:21

cannot be a Python list or dictionary.

113:24

If I try to create a dictionary with a

113:25

list as key, I would see this following

113:28

error message. The precise explanation

113:31

is outside the scope of essence of

113:32

Python, but you can sort of guess

113:34

roughly why we can do this. Dictionary

113:36

is just a collection of key-value pairs.

113:39

If my key is a Python list, and as we

113:41

know, the contents within a list can

113:43

change easily. So, our key can change.

113:46

If the key changes, it no longer unlocks

113:49

its corresponding value.

113:51

But, the reason we love Python lists is

113:53

because it's an iterable, which allows

113:56

us to run a for loop. At this point, we

113:58

know that loop is basically a superpower

114:01

in programming. Dictionary, luckily, is

114:04

also an iterable. However, doing a for

114:06

loop with dictionary is nuanced because

114:09

dictionary has both keys and values. We

114:11

need to be careful and precise about

114:13

what we're doing.

114:16

The keys method returns an iterable of

114:19

all the keys in the dictionary.

114:22

This lets us to loop through just the

114:24

keys and do something with each one,

114:26

like printing them out.

114:31

Similarly, the value method returns all

114:34

the values in the dictionary, which we

114:36

can loop through in the same way.

114:40

You might ask, "What about loop over

114:42

both the key and value simultaneously?"

114:45

And yes, that's possible. You'll need

114:47

the items method and use two separate

114:50

loop variables. The first one, K, is

114:53

key. The second one, V, is value. Here's

114:56

what the loops looks like.

115:08

>> Cool. Let's put it to use.

115:10

Another customer, Patrick, enters, asks

115:12

if we have something called Krabby Patty

115:14

in the menu. We write string Krabby

115:17

Patty in menu false, so we don't have

115:20

it.

115:21

Here, I'm also showing you interesting

115:23

property of Python dictionary. If you

115:25

don't specify dot keys or dot values,

115:27

Python would automatically assume you're

115:29

using dot keys.

115:33

Patrick then asks, "What do you have?"

115:35

So, we iterate through all the keys and

115:37

print each one of them. By the way, you

115:39

know the dot keys here can be optional.

115:43

Patrick says he only has $5, what can he

115:45

buy? We use the dot items method and

115:49

iterate through the keys and values

115:50

simultaneously. Within the loop, only if

115:53

the value is less than five, we print

115:55

the key-value pair.

115:56

Execute. Nice. Everything affordable for

115:59

Patrick here.

116:02

For our final coding example today,

116:04

let's try to combine various technique

116:06

and data structure we learned from

116:07

previous video together to truly show

116:09

the charisma of Python dictionary.

116:12

So, you probably heard about the novel

116:13

and movie series called Harry Potter.

116:15

We're going to use Python to count how

116:18

many times a certain name appear in the

116:20

first novel. You might ask, "What's the

116:22

point of doing this?" Well, I can argue

116:24

that the importance of a character is

116:27

proportional to how many times his or

116:28

her name appear in the novel.

116:30

Intuitively, we know that the name Harry

116:32

will appear the most, but exactly how

116:34

many times? And what about Ron,

116:36

Hermione, Malfoy? Who is the second most

116:39

important character? Let's find out with

116:41

Python dictionary.

116:44

I have a Python list called book, which

116:46

contains every single word of the first

116:49

novel.

116:50

It has 78,000 words.

116:53

My coding strategy is that I will

116:55

initialize a dictionary with a

116:56

character's name as a key and zero for

116:59

all their value.

117:00

The dictionary will store how many times

117:02

I've seen a character in the novel.

117:05

I will iterate through every single word

117:08

in the book. If the word match any

117:10

character's name, then I'll increment

117:12

that name's value in the dictionary by

117:14

one.

117:15

Let's execute the code.

117:18

And I print dictionary.

117:19

Harry appear 1,200 times and then we

117:22

have Ron, Hermione, and last Malfoy.

117:25

This kind of roughly aligns with my

117:27

expectation.

117:28

And also, just notice how fast Python

117:31

is. The for loop completed the entire

117:33

book almost instantaneously.

117:36

If you felt this code here is a bit

117:38

complex, I understand. Here is its

117:40

equivalent visualization.

117:42

This loop diligently examine every

117:44

single word, increment the dictionary if

117:46

necessary. For example, now the loop

117:49

variable binds to chapter.

117:51

Chapter is not in the dictionary, so the

117:54

if statement doesn't get triggered.

117:56

The word then binds to one, which is

117:59

also not in the dictionary and the if

118:00

statement doesn't get triggered.

118:02

Honestly, this loop is going to run for

118:04

a while and don't find anything

118:05

meaningful

118:06

until much later.

118:09

The word binds to Harry. Harry is indeed

118:12

in the dictionary, so I increment

118:13

Harry's value by one.

118:21

The loop runs, runs, runs, runs.

118:25

And it finds Harry again.

118:27

Harry's value increments by one.

118:30

So, you can imagine when this loop gets

118:33

to the very last word of chapter one,

118:36

the loop would have counted everyone's

118:37

name correctly into the dictionary.

118:41

Also, remember everything you saw just

118:43

now happens in less than a second.

118:46

That's just how fast Python is.

118:57

>> You embark on a journey seeking for the

118:59

truth and the wisdom of programming. You

119:02

learn various technique and data

119:03

structure. Now you can write code which

119:06

computes the factorial of any integer

119:08

using a for loop iterating over positive

119:11

integer from 1 to n.

119:13

The loop variable accumulates the

119:15

product along the way.

119:17

When the loop completes, you get your

119:18

factorial.

119:21

This is no small achievement, but you

119:23

keep going learning from friends and

119:25

sensei because you believe there's

119:27

another gem out there waiting for you.

119:30

However, the journey is harsh. For a

119:32

long time you believe some kind of loop

119:34

is the only way you can compute

119:36

factorial and there's nothing more out

119:39

there.

119:40

Until one day, you climb a mountain and

119:43

met with an old wise monk. You told him

119:45

about your mission seeking for the

119:47

elegance of programming.

119:49

He smiled and asked you,

119:51

>> Can you tell me what's the factorial of

119:53

five?

119:53

>> Oh, that's simple. It is 5 * 4 * 3 * 2 *

119:57

1.

119:58

>> How about factorial of six then?

120:00

>> That's just 6 * 5 4 3 2 1.

120:03

>> You notice something interesting.

120:05

What is this part?

120:06

>> That's just 5 * 4 3 2 1. Oh wait.

120:10

This is the factorial of five.

120:12

So, the factorial of six is the integer

120:15

six times the factorial of five.

120:17

>> Very well. Can we generalize for all

120:20

number?

120:20

>> Should be the factorial of n is the

120:23

integer n times the factorial of n minus

120:26

1.

120:27

>> Good. Take out your keyboard. Define

120:30

function factorial. What is the

120:32

factorial of one?

120:33

>> It's one. No question asked.

120:35

>> Else?

120:36

>> We said that it's the number n times the

120:38

factorial of n minus 1.

120:41

Wait, wait, wait. I'm still defining the

120:42

function. How can I be using the

120:44

function?

120:45

>> Don't worry. Give it a try. It's about

120:47

the recursive leap of faith.

120:50

>> Well, let me try.

120:54

The factorial 5 is indeed 120. This

120:56

function actually work. Wow.

121:00

If today is your first time seeing a

121:01

recursive function, you should be amazed

121:04

and confused.

121:05

So, let's slowly take a look at what

121:07

happened. We're calling the function

121:09

fact, short for factorial, on five. It

121:12

checked the if statement and is not one.

121:15

So, we entered the else case.

121:16

But now, it's n multiply with another

121:19

function call of itself. It's calling

121:21

fact of n minus one, which is factorial

121:24

4.

121:25

So, it creates a new function frame with

121:26

n of the exact same definition, but this

121:29

time, the input n is 4.

121:32

It failed the if statement and goes to

121:34

the else case.

121:35

It's calling n times fact of 3.

121:38

So, it opens another function frame with

121:40

input of 3.

121:42

Similar logic happens here. Fact 3 is

121:45

going to call n times fact 2.

121:48

And factor 2 is calling factor 1.

121:52

Okay. Here, the if statement finally

121:55

pass. We hit the base case. The function

121:57

frame returns 1. But what do we do with

121:59

this value 1 here? It's getting sent

122:02

back to its parent function frame here.

122:07

Now, the parent function frame, fact 2,

122:09

can fully evaluate the return statement,

122:11

n times 1, which is 2 times 1, and the

122:15

value 2 is sent back to its respective

122:17

parent frame,

122:19

which it will evaluate 3 times 2, 6,

122:23

and 6 is sent back to its parent frame,

122:27

which it would evaluate 4 times 6, 24.

122:31

Finally, we go back to the original

122:33

function frame, which returns 5 times

122:36

24, 120. That was a lot to digest. But

122:41

if we were to reflect on what just

122:42

happened, it's kind of like we were

122:44

peeling an onion layer by layer until we

122:47

arrive at a base case.

122:49

And then, its return value gradually

122:51

pass all the way back up.

122:56

The factorial function is the poster

122:58

child of learning recursion because it

123:00

demonstrates three important principles.

123:02

One, the function intends to call itself

123:05

during definition. This fears that the

123:07

function is trying to solve a problem

123:09

using itself. This might also be the

123:11

most unsettling part to look at because

123:14

you might wonder, wouldn't this just

123:15

lead to an infinite chain of a self

123:17

calling self calling self?

123:19

Two, the function has a base case, which

123:22

is how does it handle the smallest

123:24

problem size? For example, the factorial

123:26

of one is just one. No one's going to

123:28

question that. The base case is how the

123:31

function prevents an infinite recursive

123:33

call.

123:35

Three, the function has recursive case,

123:37

which helps to gradually reduce the

123:39

problem size. This is the most critical

123:42

part of recursive function. Notice,

123:44

while calling the function itself, the

123:46

argument is no longer factorial of n,

123:49

but factorial of n minus one.

123:52

Without doing this, your recursive

123:53

function would never get to the base

123:55

case.

123:56

These are the three characteristic you

123:58

need to remember by heart when designing

124:00

your own recursive function.

124:03

So, let me show you another example of

124:05

recursive function and see how the three

124:07

principles still apply. The goal here is

124:09

to design a function which can reverse a

124:11

string. For example, ABCD turns into

124:14

DCBA.

124:16

Generally, when solving a recursive

124:17

problem, it takes quite a bit of poking

124:19

around with experimental trial and

124:21

error.

124:23

Let's say I have ABCD here and I want to

124:25

reverse it. Here's an observation I

124:27

have. When a string is reversed, its

124:29

original first character will become the

124:32

last character.

124:34

So, I can try to break the string as the

124:37

first character A and then everything

124:39

else after it.

124:41

If someone else can magically reverse

124:43

BCD,

124:45

then I just need to stick the character

124:47

A at the very end and the string's

124:49

reversed. Simple.

124:51

But how can I reverse BCD?

124:54

Well, I can use the same process. I can

124:56

break into B and CD, the first character

125:00

and then everything afterwards.

125:02

If someone else can reverse CD into DC,

125:06

then I just need to put the B at the

125:07

very end.

125:09

Well, you notice I'm using the exact

125:11

same problem-solving methodology, but

125:13

just on a gradually smaller problem

125:15

size. I am reducing a bigger problem

125:18

into a smaller problem and using the

125:20

very same algorithm to solve the smaller

125:23

problem. Recursion is screaming to be

125:25

used.

125:27

I define the function reverse. First,

125:29

the base case. If we just have one

125:31

character, then nothing needs to be

125:33

reversed. It is just itself.

125:36

Else, if the string is longer, all we

125:39

need to do is to take the first

125:40

character and put it at the very end.

125:44

And I'll call the reverse function on

125:45

the substring from index one.

125:48

When I'm calling the reverse function,

125:50

I'm implicitly trusting it to return the

125:53

correct results to me.

125:55

I am trusting it to correctly reverse a

125:57

substring so I can combine it with the

125:59

first character later on.

126:01

I am confidently trusting this function

126:03

call even though it seems untrustworthy

126:06

because I'm still in the process of

126:07

defining the function.

126:09

And this unceremonious trust is the

126:12

essence of the recursive leap of faith.

126:15

It's a secret covenant between the

126:17

programmer and the recursive function.

126:21

If a visualization helps you to solidify

126:24

the understanding, here's how the

126:26

reverse function looks like.

127:23

>> Today's video is an informal tourist

127:25

guide to the concept of recursion in

127:27

programming.

127:29

Recursion is often one of those topics

127:31

with an infinite rabbit hole and very

127:32

high skill ceiling. This video alone

127:35

cannot make you a recursion master. I'm

127:38

here to spark your interest by

127:39

programming and share something I

127:41

personally find very elegant when I was

127:44

learning Python in college.

127:46

Let's end the video on a quote.

127:48

Beauty is everywhere. It is not that

127:50

she's lacking to our eye, but our eyes

127:52

which fail to perceive her. But really,

127:55

I can change the word beauty into

127:56

recursion because recursion is

127:59

everywhere in our life and in computer

128:01

science. It's our programmer's duty to

128:04

perceive them.

128:08

My plan for the future is that hopefully

128:10

one day I can make educational video

128:12

full-time. The potential candidate for

128:15

my next courses are operating system,

128:18

computer architecture, large language

128:20

model full stack.

128:22

Nowadays, YouTube is populated with

128:24

contents of high production value. Yet,

128:26

you chose to sit through 14 episodes of

128:29

Essence of Python to learn about coding.

128:31

You don't know who I am, and I don't

128:33

know who you are. Much like two

128:35

strangers going on journey together.

128:37

This reminds me of my favorite anime,

128:39

Samurai Champloo, which tells such a

128:41

story. The three main character, Jin,

128:44

Mugen, Fu, have never met, but they went

128:48

on a journey from Edo to Nagasaki

128:50

seeking for samurai with a scent of

128:52

sunflower. And this anime has quite a

128:54

beautiful ending song, Shiki no Uta.

128:57

I'd share that with you,

128:59

and let's end on that.

129:05

>> [music]

129:32

[music]

129:42

[music]

129:51

[music]

Interactive Summary

This video provides a comprehensive introduction to core programming concepts using Python. It covers variables and assignment, the importance of Boolean logic and conditional statements, list data structures, various looping techniques including for loops and nested loops, functions and their scope, the nuances of value vs. reference, dictionary data structures, and finally, recursion. The instruction emphasizes 'programming thinking' as a fundamental skill for leveraging AI and creating impactful projects, moving beyond simple 'vibe coding'.

Suggested questions

4 ready-made prompts