Giải Tin Học 10 trang 136
Lời giải chi tiết SGK Lớp 10 · Môn Tin Há»c · Trang 136–141
Bài 28: Phạm vi của biến
⚠️ Lưu ý: Phần văn bản gốc bị lỗi font (mã hóa hỏng), nên một số đoạn mã lệnh và con số trong ví dụ được thầy phục dựng lại theo đúng nội dung chuẩn của bài học. Phần khái niệm và lời giải bài tập đều chính xác và đầy đủ.
🔍 Kiến thức cần nhớ
1. Biến địa phương (local) – khai báo bên trong hàm
- Mọi biến được khai báo (gán giá trị) bên trong một hàm đều là biến địa phương, chỉ có hiệu lực bên trong hàm đó.
- Khi hàm kết thúc, biến địa phương cũng biến mất. Gọi biến này ở chương trình chính sẽ báo lỗi (NameError).
2. Biến toàn cục (global) – khai báo bên ngoài hàm
- Biến khai báo ở chương trình chính (ngoài mọi hàm) gọi là biến toàn cục.
- Bên trong hàm được phép đọc (truy cập) giá trị của biến toàn cục.
- Nhưng không thể thay đổi giá trị biến toàn cục từ bên trong hàm. Nếu trong hàm có lệnh gán cho biến trùng tên, Python sẽ tạo ra một biến địa phương mới chứ không động đến biến toàn cục.
3. Từ khóa global
- Muốn thay đổi biến toàn cục ngay bên trong hàm, ta phải khai báo lại biến đó với từ khóa
global.
def f():
global t
t = 2 * t + 1
return t
💡 Mẹo nhớ: "Trong ra ngoài thì xem được, ngoài vào trong thì không sửa được – trừ khi có global."
⚠️ Lưu ý thi: Dạng bài cho một hàm thay đổi biến rồi hỏi giá trị biến bên ngoài là dạng cực kỳ hay ra. Đáp án gần như luôn là: biến ngoài giữ nguyên (vì hàm chỉ làm việc với bản sao địa phương).
⚙️ Bài tập
Câu 1 — Hai câu hỏi mở đầu bài (trang 136 – 137)
Đề bài:
- Một biến được định nghĩa trong chương trình chính (bên ngoài các hàm) thì sẽ được sử dụng như thế nào bên trong các hàm?
- Một biến được khai báo bên trong một hàm thì có sử dụng được ở bên ngoài hàm đó hay không?
Cách 1 — Dựa vào định nghĩa phạm vi biến
Câu 1: Biến toàn cục đó đọc được (truy cập được) bên trong hàm, nghĩa là hàm có thể lấy giá trị của nó để tính toán. Tuy nhiên hàm không thể thay đổi giá trị của biến toàn cục này (mọi lệnh gán bên trong sẽ tạo biến địa phương mới), trừ khi dùng từ khóa global.
Câu 2: Không. Biến khai báo bên trong hàm là biến địa phương, chỉ tồn tại và có hiệu lực trong phạm vi hàm. Ra khỏi hàm, biến đó không còn, nên không dùng được ở bên ngoài.
Câu 2 — Câu hỏi mục 1 (trang 138)
Đề bài:
- Giả sử có các lệnh sau:
>>> a, b = 1, 2
>>> def f(a, b):
a = a + b
b = a - b
return a + b
Giá trị của a, b bằng bao nhiêu sau khi thực hiện:
- a)
f(1, 2) - b)
f(10, 20)
- Ta có thể khai báo một biến bên trong hàm trùng tên với biến đã khai báo trước đó bên ngoài hàm không?
Cách 1 — Phân biệt biến địa phương và biến toàn cục
Điểm mấu chốt: a và b bên ngoài là biến toàn cục (= 1 và 2). Tham số a, b cùng các phép gán bên trong hàm chỉ là biến địa phương. Dù hàm tính toán thế nào, biến toàn cục không bị thay đổi.
- a) Sau khi gọi
f(1, 2): giá trị a = 1, b = 2 (không đổi). - b) Sau khi gọi
f(10, 20): giá trị a = 1, b = 2 (vẫn không đổi).
Hàm chỉ trả về một giá trị tạm thời, còn a, b ngoài hàm luôn giữ nguyên 1 và 2.
Câu 2: Có. Hoàn toàn được phép. Biến trong hàm và biến ngoài hàm dù trùng tên vẫn là hai biến khác nhau, độc lập. Việc thay đổi biến trong hàm không ảnh hưởng đến biến ngoài hàm.
⚠️ Lưu ý thi: Nhiều bạn nhầm rằng gọi hàm xong thì biến ngoài bị đổi theo. Hãy nhớ: muốn đổi biến toàn cục bắt buộc phải có global.
Câu 3 — Câu hỏi mục 2 / Hoạt động 2 (trang 139)
Đề bài: Giả sử hàm f(x, y) được định nghĩa như sau:
>>> def f(x, y):
N = 2 * (x + 1)
print(N)
Kết quả nào được in ra khi thực hiện các lệnh sau?
>>> N = 10
>>> f(1, 2)
Cách 1 — Truy vết từng biến
- Lệnh
N = 10tạo biến toàn cụcN = 10. - Khi gọi
f(1, 2): trong hàmx = 1,y = 2. LệnhN = 2(x+1)tạo biến địa phươngN = 2(1+1) = 4, rồiprint(N)in ra 4. - Sau khi hàm kết thúc, biến toàn cục
Nvẫn bằng 10 (không bị ảnh hưởng).
→ Màn hình in ra: 4
Câu 4 — Thực hành, Nhiệm vụ 1 (trang 138)
Đề bài: Viết hàm với đầu vào là danh sách A chứa các số và số x. Hàm trả lại danh sách B từ A bằng cách chỉ giữ lại các phần tử lớn hơn hoặc bằng x.
Cách 1 — Dùng vòng lặp for và chỉ số
def Loc(A, x):
B = [] # B là biến địa phương, khai báo trong hàm
for i in range(len(A)):
if A[i] >= x:
B.append(A[i]) # bổ sung phần tử thỏa điều kiện
return B
# Ví dụ chạy thử
A = [3, 7, 1, 9, 4, 10]
print(Loc(A, 5)) # [7, 9, 10]
Cách 2 — Dùng list comprehension (gọn, nhanh)
def Loc(A, x):
return [phantu for phantu in A if phantu >= x]
💡 Mẹo nhớ: [biểu_thức for x in danh_sách if điều_kiện] là cách "lọc danh sách" siêu gọn trong Python.
Câu 5 — Thực hành, Nhiệm vụ 2 (trang 139 – 140)
Đề bài: Viết hàm với đầu vào là xâu kí tự Str và số c, đầu ra là danh sách các từ được tách ra từ Str, đã chuyển dạng chữ tùy theo c:
- c = 0: chuyển tất cả thành chữ in HOA
- c = 1: chuyển tất cả thành chữ in thường
- c = 2: viết hoa kí tự đầu mỗi từ
Các lệnh hỗ trợ: .split() (tách từ), .upper(), .lower(), .title().
Cách 1 — Tách từ rồi xử lý từng phần tử
def Tach_tu(Str, c):
A = Str.split() # tách xâu thành danh sách các từ
for i in range(len(A)):
if c == 0:
A[i] = A[i].upper() # in hoa
if c == 1:
A[i] = A[i].lower() # in thường
if c == 2:
A[i] = A[i].title() # hoa chữ cái đầu
return A
# Ví dụ
print(Tach_tu("hoc tin hoc rat vui", 0)) # ['HOC', 'TIN', 'HOC', 'RAT', 'VUI']
print(Tach_tu("HOC TIN HOC", 1)) # ['hoc', 'tin', 'hoc']
print(Tach_tu("hoc tin hoc", 2)) # ['Hoc', 'Tin', 'Hoc']
Cách 2 — Dùng cấu trúc rẽ nhánh if...elif
def Tach_tu(Str, c):
A = Str.split()
for i in range(len(A)):
if c == 0:
A[i] = A[i].upper()
elif c == 1:
A[i] = A[i].lower()
elif c == 2:
A[i] = A[i].title()
return A
⚠️ Lưu ý:.title()viết hoa kí tự đầu mỗi từ, còn.capitalize()chỉ viết hoa kí tự đầu của cả xâu. Đề bài yêu cầu mỗi từ nên dùng.title().
Câu 6 — Thực hành, Nhiệm vụ 3 (trang 140 – 141)
Đề bài: Viết chương trình, mỗi việc tách riêng thành một hàm:
- Nhập một dãy số nguyên cách nhau bởi dấu cách, đưa vào danh sách A và in A.
- Trích từ A ra danh sách B gồm các phần tử lớn hơn 0, in B.
- Trích từ A ra danh sách C gồm các phần tử nhỏ hơn 0, in C.
Cách 1 — Mỗi nhiệm vụ một hàm riêng
def Nhap():
s = input("Nhập dãy số nguyên (cách nhau bởi dấu cách): ")
A = s.split() # tách thành danh sách các xâu
for i in range(len(A)):
A[i] = int(A[i]) # chuyển từng phần tử về số nguyên
return A
def Loc_duong(A):
B = []
for x in A:
if x > 0:
B.append(x)
return B
def Loc_am(A):
C = []
for x in A:
if x < 0:
C.append(x)
return C
# Chương trình chính
A = Nhap()
print("Danh sách A:", A)
B = Loc_duong(A)
print("Danh sách B (số dương):", B)
C = Loc_am(A)
print("Danh sách C (số âm):", C)
Cách 2 — Gộp phần lọc bằng list comprehension
def Nhap():
return [int(x) for x in input("Nhập dãy số: ").split()]
A = Nhap()
print("A:", A)
print("B:", [x for x in A if x > 0])
print("C:", [x for x in A if x < 0])
Câu 7 — Luyện tập 1 (trang 141)
Đề bài: Viết hàm có:
- Đầu vào là danh sách các phần tử là xâu kí tự.
- Đầu ra là danh sách các phần tử là kí tự đầu tiên của mỗi xâu tương ứng.
Cách 1 — Lấy kí tự ở chỉ số 0 của mỗi xâu
def Kytudau(A):
B = []
for s in A:
B.append(s[0]) # s[0] là kí tự đầu tiên của xâu s
return B
# Ví dụ
print(Kytudau(["Ha Noi", "Hue", "Da Nang"])) # ['H', 'H', 'D']
Cách 2 — List comprehension
def Kytudau(A):
return [s[0] for s in A]
⚠️ Lưu ý: Nếu danh sách có xâu rỗng""thìs[0]sẽ báo lỗi. Khi cần an toàn, có thể thêm điều kiệnif len(s) > 0.
Câu 8 — Luyện tập 2 (trang 141)
Đề bài: Viết hàm f(A) với đầu vào là danh sách A, đầu ra là hai danh sách B, C:
- B: gồm các phần tử có chỉ số chẵn của A.
- C: gồm các phần tử có chỉ số lẻ của A.
Cách 1 — Xét chỉ số i chẵn/lẻ
def f(A):
B = []
C = []
for i in range(len(A)):
if i % 2 == 0: # chỉ số chẵn: 0, 2, 4,...
B.append(A[i])
else: # chỉ số lẻ: 1, 3, 5,...
C.append(A[i])
return B, C
# Ví dụ
B, C = f([10, 20, 30, 40, 50])
print("B:", B) # [10, 30, 50]
print("C:", C) # [20, 40]
Cách 2 — Dùng kĩ thuật cắt danh sách (slicing)
def f(A):
B = A[0::2] # bắt đầu từ 0, bước nhảy 2 → chỉ số chẵn
C = A[1::2] # bắt đầu từ 1, bước nhảy 2 → chỉ số lẻ
return B, C
💡 Mẹo nhớ:A[start::step]– cú pháp cắt danh sách rất mạnh:A[1::2]lấy ngay tất cả phần tử ở vị trí lẻ.
Câu 9 — Vận dụng 1 (trang 141)
Đề bài: Viết hàm có hai tham số m, n. Trả lại hai giá trị:
- ƯCLN (ước chung lớn nhất) của m, n.
- BCNN (bội chung nhỏ nhất) của m, n.
Gợi ý: dùng công thức ƯCLN(m,n) × BCNN(m,n) = m × n.
Cách 1 — Thuật toán Euclid tìm ƯCLN
def UCLN(m, n):
while n != 0:
m, n = n, m % n # thuật toán Euclid
return m
def UC_BC(m, n):
a = UCLN(m, n) # ước chung lớn nhất
b = m * n // a # bội chung nhỏ nhất = m*n / ƯCLN
return a, b
# Ví dụ
print(UC_BC(12, 18)) # (6, 36)
Cách 2 — Dùng thư viện math (Python 3.9+)
import math
def UC_BC(m, n):
a = math.gcd(m, n) # hàm gcd có sẵn
b = m * n // a
return a, b
⚠️ Lưu ý thi: Khi tính BCNN nên dùng phép chia lấy nguyên // để kết quả là số nguyên, tránh ra số thực. Phải tính ƯCLN trước rồi mới suy ra BCNN.
💡 Mẹo nhớ thuật toán Euclid: "Lấy số lớn chia số bé, thay bằng số dư, lặp đến khi dư bằng 0 thì số còn lại là ƯCLN."
Câu 10 — Vận dụng 2 (trang 141)
Đề bài: Viết chương trình nhập ba số tự nhiên day, month, year (cách nhau bởi dấu cách), biểu diễn ngày – tháng – năm. Chương trình kiểm tra và in ra thông báo dữ liệu nhập vào có hợp lệ hay không.
Cách 1 — Hàm kiểm tra theo từng điều kiện ngày, tháng, năm nhuận
def nam_nhuan(year):
# năm nhuận: chia hết cho 4 nhưng không chia hết cho 100,
# hoặc chia hết cho 400
return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
def kiem_tra_ngay(day, month, year):
# 1) Kiểm tra năm
if year < 1:
return False
# 2) Kiểm tra tháng
if month < 1 or month > 12:
return False
# 3) Xác định số ngày tối đa của tháng
thang_31 = [1, 3, 5, 7, 8, 10, 12]
if month in thang_31:
max_day = 31
elif month == 2:
max_day = 29 if nam_nhuan(year) else 28
else:
max_day = 30
# 4) Kiểm tra ngày
if day < 1 or day > max_day:
return False
return True
# Chương trình chính
s = input("Nhập ngày tháng năm (day month year): ")
day, month, year = map(int, s.split())
if kiem_tra_ngay(day, month, year):
print(day, "/", month, "/", year, "là ngày hợp lệ.")
else:
print(day, "/", month, "/", year, "KHÔNG hợp lệ.")
Cách 2 — Dùng thư viện datetime để kiểm tra
import datetime
def kiem_tra_ngay(day, month, year):
try:
datetime.date(year, month, day) # nếu sai, Python tự báo lỗi
return True
except ValueError:
return False
s = input("Nhập day month year: ")
day, month, year = map(int, s.split())
print("Hợp lệ" if kiem_tra_ngay(day, month, year) else "Không hợp lệ")
⚠️ Lưu ý thi: Phần khó nhất là tháng 2 năm nhuận (28 hay 29 ngày). Quy tắc năm nhuận: chia hết cho 4 và không chia hết cho 100, hoặc chia hết cho 400. Ví dụ 2000 là năm nhuận, nhưng 1900 thì không.
🎯 Ghi nhớ: - Biến khai báo trong hàm = biến địa phương, chỉ sống trong hàm. - Biến khai báo ngoài hàm = biến toàn cục: trong hàm đọc được nhưng không sửa được (trừ khi dùng global). - Hàm gọi xong, biến toàn cục không đổi – đây là điểm bẫy hay gặp nhất. - Hai biến trùng tên trong/ngoài hàm là hai biến độc lập.