ይህ ትምህርት ገና ወደ አማርኛ አልተተረጎመም፤ ስለዚህ በእንግሊዝኛ ቀርቧል። የእንግሊዝኛውን ገጽ ክፈቱ
Scope
In lesson 5.1 you saw that each call gets its own frame of names, gone when the call
ends. That one idea explains a whole family of surprises: names that vanish, a
total that isn't the total you meant, and lists that change from inside a
function. By the end you'll predict all of them.
Names made in a call stay in the call
Predict what this prints. Look at the last line of the output when you reveal it.
ውጤቱን ገምቱ
Decide before you look. Guessing wrong is how this sticks.
def add_up(prices):
total = sum(prices)
return total
add_up([120, 80])
print(total)Python prints
Traceback (most recent call last):
File "<your code>", line 6, in <module>
print(total)
^^^^^
NameError: name 'total' is not definedtotal was made inside the call, so it belonged to that call's frame. When the call ended, the frame and total went with it. The returned value, 200, was never given a name either.
A name made inside a function is
:
it lives in that call's frame and nowhere else. Names made outside every function are
.
Where a name can be used is its
.
To use the result outside, return it and give it a name: bill = add_up([120, 80]).
A local name can even share its spelling with a global one. They're still two names:
Two names called total
Press Next to run one line at a time. Each arrow shows the object a name refers to. Each call gets its own frame of names, below the frame that called it.Each row is one step: the line that just ran, and the object each name refers to after it, frame by frame, oldest first.
Frames, oldest first: global. total refers to an int, 0.
Step 1 of 6
Step 1 of 6. Line 1: total = 0. total now refers to a new int, 0.
| Step | Line | Names and objects |
|---|---|---|
| 1 | 1 |
|
| 2 | 3 |
|
| 3 | 7 |
|
| 4 | 4 |
|
| 5 | 5 |
|
| 6 | 7 |
|
Line 4 made a new total in the call's frame. The global total is still 0 at the end.
Reading a global, and assigning one
A function can read a global name. Python looks in the call's frame first, and if the name isn't there, in the global names:
rate = 0.15
def vat(price):
return price * (1 + rate)
print(vat(1000))In the editor, press Escape then Tab to move on.
Assigning is different. Predict what happens here:
ውጤቱን ገምቱ
Decide before you look. Guessing wrong is how this sticks.
count = 0
def add_visit():
count = count + 1
add_visit()
print(count)Python prints
Traceback (most recent call last):
File "<your code>", line 6, in <module>
add_visit()
~~~~~~~~~^^
File "<your code>", line 4, in add_visit
count = count + 1
^^^^^
UnboundLocalError: cannot access local variable 'count' where it is not associated with a valueBecause count is assigned inside the function, Python treats it as local for the whole function. So count + 1 reads the local count, which has no value yet.
Any assignment to a name inside a function makes that name local to the function,
from its first line. The error says exactly that: a local variable with no value yet.
Python has a way to say "I mean the global one", the global statement:
count = 0
def add_visit():
global count
count = count + 1
add_visit()
print(count)In the editor, press Escape then Tab to move on.
It works, but avoid it. When any function can change a global, you have to read every function to know what a name is, and a function is hard to reuse or test. The clean pattern is pass values in, return values out:
def add_visit(count):
return count + 1
visits = 0
visits = add_visit(visits)
print(visits)In the editor, press Escape then Tab to move on.
Lists as parameters
A parameter is a new name for the caller's object, the rule from lesson 4.8. Predict both programs before you look.
ውጤቱን ገምቱ
Decide before you look. Guessing wrong is how this sticks.
def change(lst):
lst.append(9)
a = [1]
change(a)
print(a)Python prints
[1, 9]
lst and a refer to the same list. append changes that list, so a sees the 9.
ውጤቱን ገምቱ
Decide before you look. Guessing wrong is how this sticks.
def rebind(lst):
lst = [0]
a = [1]
rebind(a)
print(a)Python prints
[1]
lst = [0] makes a new list and moves the local name lst to it. The caller's list, and a, are untouched.
Step through both. In change, two names in two frames refer to one list:
change(a): one list, two names
Press Next to run one line at a time. Each arrow shows the object a name refers to. Each call gets its own frame of names, below the frame that called it.Each row is one step: the line that just ran, and the object each name refers to after it, frame by frame, oldest first.
Frames, oldest first: global.
Step 1 of 5
Step 1 of 5. Line 1: def change(lst):. Nothing in memory changed.
| Step | Line | Names and objects |
|---|---|---|
| 1 | 1 |
|
| 2 | 4 |
|
| 3 | 5 |
|
| 4 | 2 |
|
| 5 | 5 |
|
In rebind, only the local name moves:
rebind(a): the local name moves
Press Next to run one line at a time. Each arrow shows the object a name refers to. Each call gets its own frame of names, below the frame that called it.Each row is one step: the line that just ran, and the object each name refers to after it, frame by frame, oldest first.
Frames, oldest first: global.
Step 1 of 5
Step 1 of 5. Line 1: def rebind(lst):. Nothing in memory changed.
| Step | Line | Names and objects |
|---|---|---|
| 1 | 1 |
|
| 2 | 4 |
|
| 3 | 5 |
|
| 4 | 2 |
|
| 5 | 5 |
|
Changing the object shows through every name; moving a name doesn't. If a function should give back a new list, return it.
ጥያቄ
def reset(scores): scores = []. After data = [5, 7] and reset(data), what is data?
Where Python looks
When you use a name, Python searches four scopes in order, called LEGB, and uses the first match:
| Scope | Its names |
|---|---|
| Local | Names made in the current call |
| Enclosing | Names in a function around this one (functions inside functions, later) |
| Global | Names made at the top level of the program |
| Built-in | Python's own names: print, len, sum |
መልመጃ
No more global
This works, but add_price changes a global. Rewrite it so add_price(total, price)
takes the current total and returns the new one, with no global. It already prints
200; it should still print 200 when you're done.
Your code
total = 0
def add_price(price):
global total
total = total + price
add_price(120)
add_price(80)
print(total)In the editor, press Escape then Tab to move on.
መፍትሄውን አሳይHide the solution
This is one way to solve it, not the only one. If yours prints the same thing, it works.
def add_price(total, price):
return total + price
total = 0
total = add_price(total, 120)
total = add_price(total, 80)
print(total)ዋና ዋና ነጥቦች
- Names made inside a call are local: they live in that call's frame and disappear when it ends.
- A local name and a global name with the same spelling are two different names.
- Reading a global works; assigning a name anywhere in a function makes it local, hence
UnboundLocalError. - Avoid
global: pass values in, return values out. - A parameter shares the caller's object: changing it shows outside; moving the name doesn't.