Skip to content

Commit 9639851

Browse files
authored
Merge pull request #13 from tajirdev/fix_exercises/06_Scope_and_Namespaces_issue
fixed the pr issue
2 parents aebd16d + 18795b1 commit 9639851

5 files changed

Lines changed: 547 additions & 0 deletions

File tree

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Exercise 06 - Scope Station: Reactor Rescue (Scope and Namespaces)
2+
3+
## Description
4+
Orbital Station Alpha is failing! Engineers rushed the code and left variables in the wrong places: some are trapped inside functions, some are missing the right keyword, and some are hiding Python's own tools.
5+
6+
This is a **debugging game**. `scopes.py` is already written, but it is *almost* working. Your job in each level is to figure out **where each variable must live** (and which keyword, if any, it needs) so the system runs.
7+
8+
Remember the question from the lesson: *"Where does this name live, and who needs to see it?"*
9+
10+
> Do not rename the functions. The tests call them by name. You decide where the variables go.
11+
12+
13+
---
14+
15+
## Levels
16+
17+
### Level 1 - Power Grid (Local vs. Global)
18+
`show_banner()` crashes with a `NameError`. The station name is created inside `boot_system()`, but two functions need it.
19+
* **Your job**: make both `boot_system()` and `show_banner()` work.
20+
* **Expected**: `show_banner()` returns `"=== Orbital Station Alpha ==="`.
21+
22+
> **Next step:** Run `python check.py 06`. Once Level 1 passes, remove the `@pytest.mark.skip` line above `test_level2` in `test_scopes.py`.
23+
24+
### Level 2 - Life Support (Enclosing Scope)
25+
`build_oxygen_monitor()` returns an inner function `read_level()`, but it can't find the oxygen value.
26+
* **Your job**: put `oxygen` where `read_level()` can find it by looking outward, and don't use a global.
27+
* **Expected**: the monitor returns `"Oxygen at 100%"`.
28+
29+
> **Next step:** Unlock `test_level3`.
30+
31+
### Level 3 - Comms Array (Built-in Scope)
32+
`summarize_signals()` fails with `TypeError: ... object is not callable`. Something is hiding Python's built-in tools.
33+
* **Your job**: find what is shadowing the built-ins and fix it.
34+
* **Expected**: `"3 signals, strength 49"`.
35+
36+
> **Next step:** Unlock `test_level4`.
37+
38+
### Level 4 - Reactor Core (`UnboundLocalError`)
39+
`add_bonus_power()` crashes with `UnboundLocalError`.
40+
* **Your job**: fix it by sending the value **in** with a parameter and sending the result **out** with `return`. The global `power` must stay `50`, and `global` is not allowed in this level.
41+
* **Expected**: `add_bonus_power(50)` returns `60`.
42+
43+
> **Next step:** Unlock `test_level5`.
44+
45+
### Level 5 - Cargo Bay (Mutable Objects)
46+
`load_crate()` adds items to a list that vanishes when the function ends, and `get_manifest()` can't find it.
47+
* **Your job**: make both functions share the same list. You don't need `global`, because you only change the list's contents.
48+
* **Expected**: loading `"Titanium"` then `"Ice"` gives a manifest ending in `["Titanium", "Ice"]`.
49+
50+
> **Next step:** Unlock `test_level6`.
51+
52+
### Level 6 - Alarm System (`global`)
53+
`trigger_alarm()` should count alarms in the global `alarm_count`, but crashes.
54+
* **Your job**: let the function rebind the global variable.
55+
* **Expected**: three calls return `1`, `2`, `3` (from a fresh start) and `alarm_count` ends up updated.
56+
57+
> **Next step:** Unlock `test_level7`.
58+
59+
### Level 7 - Drone Memory (`nonlocal`)
60+
Each drone made by `make_drone_counter()` should remember how many scans it did, but `scan()` crashes.
61+
* **Your job**: let the inner function update the enclosing variable.
62+
* **Expected**: one drone counts `1, 2, 3`, and a second drone starts again at `1`.
63+
64+
> **Next step:** Unlock `test_level8`.
65+
66+
### Level 8 - Diagnostics (`globals()` and `locals()`)
67+
Complete the three helper functions in the `LEVEL 8` section:
68+
* `list_local_names(a, b)`: return a **sorted list** of the names in the function's local namespace.
69+
* `is_global(name)`: return `True` if `name` exists in the global namespace.
70+
* `probe_hidden()`: try to read `secret_code` (it only exists inside `_make_secret()`). Return `True` if Python raises `NameError`.
71+
72+
> **Next step:** Unlock `test_level9`.
73+
74+
### Level 9 - BOSS: Reactor Boot Sequence
75+
`run_station()` has **three** different scope bugs at once. Use everything you have learned.
76+
* **Expected**: `"Checks: 3 | Passed: 2 | Peak: 91"`.
77+
78+
> **Next step:** If Level 9 passes, congratulations! You saved the station.
79+
80+
---
81+
82+
## How to Run the Tests
83+
Run the following command from the repository root:
84+
```bash
85+
python check.py 06
86+
```
87+
88+
Or run directly with pytest:
89+
```bash
90+
pytest exercises/foundations/06_scopes/test_scopes.py -v
91+
```
92+
93+
---
94+
95+
## Resources & Notes
96+
Review the concepts covered in this exercise in:
97+
* [The Python Ledger Curriculum: Scope and Namespaces](https://thepythonledger.github.io/Docusaurus-engine/lessons/code-organization/scope-and-namespaces)
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# ORBITAL STATION ALPHA - Reactor Rescue
2+
# Every system below is almost working. Find WHERE each variable should live.
3+
# Do not rename the functions - the tests call them by name.
4+
5+
6+
# LEVEL 1 - Power Grid
7+
def boot_system():
8+
STATION_NAME = "Orbital Station Alpha"
9+
return f"Booting {STATION_NAME}..."
10+
11+
12+
def show_banner():
13+
return f"=== {STATION_NAME} ==="
14+
15+
16+
# LEVEL 2 - Life Support
17+
def calibrate_sensors():
18+
oxygen = 100
19+
return "Sensors calibrated"
20+
21+
22+
def build_oxygen_monitor():
23+
def read_level():
24+
return f"Oxygen at {oxygen}%"
25+
26+
return read_level
27+
28+
29+
# LEVEL 3 - Comms Array
30+
list = [12, 7, 30] # incoming signal strengths
31+
sum = 0 # total strength
32+
33+
34+
def summarize_signals():
35+
return f"{len(list)} signals, strength {sum(list)}"
36+
37+
38+
# LEVEL 4 - Reactor Core
39+
power = 50
40+
41+
42+
def add_bonus_power():
43+
print("Current power:", power)
44+
power = power + 10
45+
return power
46+
47+
48+
# LEVEL 5 - Cargo Bay
49+
def load_crate(item):
50+
cargo = []
51+
cargo.append(item)
52+
53+
54+
def get_manifest():
55+
return cargo
56+
57+
58+
# LEVEL 6 - Alarm System
59+
alarm_count = 0
60+
61+
62+
def trigger_alarm():
63+
alarm_count = alarm_count + 1
64+
return alarm_count
65+
66+
67+
# LEVEL 7 - Drone Memory
68+
def make_drone_counter():
69+
scans = 0
70+
71+
def scan():
72+
scans = scans + 1
73+
return scans
74+
75+
return scan
76+
77+
78+
# LEVEL 8 - Diagnostics
79+
def _make_secret():
80+
secret_code = 42
81+
return "secret stored"
82+
83+
84+
def list_local_names(a, b):
85+
c = a + b
86+
# Return a sorted list of the names in THIS function's local namespace.
87+
pass
88+
89+
90+
def is_global(name):
91+
# Return True if `name` exists in the global namespace.
92+
pass
93+
94+
95+
def probe_hidden():
96+
_make_secret()
97+
# Try to read `secret_code` here. Return True if Python raises NameError
98+
# (it is hidden inside _make_secret), otherwise return False.
99+
pass
100+
101+
102+
# LEVEL 9 - BOSS: Reactor Boot Sequence
103+
def configure_reactor():
104+
REACTOR_TARGET = 80
105+
return "Reactor configured"
106+
107+
108+
readings = [72, 91, 85]
109+
max = 0 # highest reading seen so far
110+
111+
112+
def run_station():
113+
checks = 0
114+
115+
def run_check(reading):
116+
checks = checks + 1
117+
return reading >= REACTOR_TARGET
118+
119+
results = [run_check(r) for r in readings]
120+
highest = max(readings)
121+
return f"Checks: {checks} | Passed: {results.count(True)} | Peak: {highest}"
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# ORBITAL STATION ALPHA - Reactor Rescue (reference solution)
2+
3+
# LEVEL 1 - Power Grid: shared by two functions -> module level
4+
STATION_NAME = "Orbital Station Alpha"
5+
6+
7+
def boot_system():
8+
return f"Booting {STATION_NAME}..."
9+
10+
11+
def show_banner():
12+
return f"=== {STATION_NAME} ==="
13+
14+
15+
# LEVEL 2 - Life Support: lives in the enclosing function
16+
def calibrate_sensors():
17+
return "Sensors calibrated"
18+
19+
20+
def build_oxygen_monitor():
21+
oxygen = 100
22+
23+
def read_level():
24+
return f"Oxygen at {oxygen}%"
25+
26+
return read_level
27+
28+
29+
# LEVEL 3 - Comms Array: don't shadow built-ins
30+
signals = [12, 7, 30]
31+
32+
33+
def summarize_signals():
34+
return f"{len(signals)} signals, strength {sum(signals)}"
35+
36+
37+
# LEVEL 4 - Reactor Core: parameter + return instead of global
38+
power = 50
39+
40+
41+
def add_bonus_power(current_power):
42+
print("Current power:", current_power)
43+
return current_power + 10
44+
45+
46+
# LEVEL 5 - Cargo Bay: shared mutable list, no `global` needed
47+
cargo = []
48+
49+
50+
def load_crate(item):
51+
cargo.append(item)
52+
53+
54+
def get_manifest():
55+
return cargo
56+
57+
58+
# LEVEL 6 - Alarm System: rebinding a global needs `global`
59+
alarm_count = 0
60+
61+
62+
def trigger_alarm():
63+
global alarm_count
64+
alarm_count = alarm_count + 1
65+
return alarm_count
66+
67+
68+
# LEVEL 7 - Drone Memory: rebinding an enclosing variable needs `nonlocal`
69+
def make_drone_counter():
70+
scans = 0
71+
72+
def scan():
73+
nonlocal scans
74+
scans = scans + 1
75+
return scans
76+
77+
return scan
78+
79+
80+
# LEVEL 8 - Diagnostics
81+
def _make_secret():
82+
secret_code = 42
83+
return "secret stored"
84+
85+
86+
def list_local_names(a, b):
87+
c = a + b
88+
return sorted(locals().keys())
89+
90+
91+
def is_global(name):
92+
return name in globals()
93+
94+
95+
def probe_hidden():
96+
_make_secret()
97+
try:
98+
secret_code
99+
except NameError:
100+
return True
101+
return False
102+
103+
104+
# LEVEL 9 - BOSS: Reactor Boot Sequence
105+
REACTOR_TARGET = 80
106+
readings = [72, 91, 85]
107+
108+
109+
def configure_reactor():
110+
return "Reactor configured"
111+
112+
113+
def run_station():
114+
checks = 0
115+
116+
def run_check(reading):
117+
nonlocal checks
118+
checks = checks + 1
119+
return reading >= REACTOR_TARGET
120+
121+
results = [run_check(r) for r in readings]
122+
highest = max(readings)
123+
return f"Checks: {checks} | Passed: {results.count(True)} | Peak: {highest}"

0 commit comments

Comments
 (0)