Python

Những chỗ Python khác C++

Chương 0 · Bài 0.1

2

Python trong khóa học

Từ bài sau, mọi code đều là Python: pandas, NumPy, scikit-learn, PyTorch.

Vòng lặp, hàm, thuật toán từ C++ vẫn dùng như cũ.

Bài này học những chỗ dễ làm sai:

  • chia, lấy dư với số âm;
  • hai biến dùng chung một list;
  • notebook nhớ biến cũ.
3

Mục tiêu

  • Tính đúng phép chia //, % với số âm; so sánh số thực.
  • Biết khi nào hai biến dùng chung một list, và cách sao chép list.
  • Chọn list, set hay dict theo độ phức tạp; đo thời gian chạy.
  • Đọc, ghi file CSV; đọc thông báo lỗi để sửa code.
4

Thụt lề thay cho dấu ngoặc

def passed_scores(values, threshold=5.0):
    result = []
    for value in values:
        if value >= threshold:
            result.append(value)
    return result
  • Dấu : mở một khối.
  • Các dòng trong cùng khối thụt lề như nhau.
  • return ngang hàng for: chạy sau khi lặp xong.
  • range(1, 5) lấy 1, 2, 3, 4.
5

Notebook nhớ lần chạy gần nhất

Sửa n mà chưa chạy lại ô dưới thì total vẫn là 6.1. Chạy cả hai ôn = 3total = sum(range(n + 1))total = 62. Sửa n, chỉ chạy ô trênn = 5total = sum(range(n + 1))total = 6cũ3. Chạy lại ô dướin = 5total = sum(range(n + 1))total = 15
Sửa n mà chưa chạy lại ô dưới thì total vẫn là 6.

Trước khi nộp: Restart & Run all.

6

Chạy trên Colab và Kaggle

  • Colab: Runtime → Change runtime type → T4 GPU.
  • Kaggle: Session options → Accelerator; cần xác minh số điện thoại.
  • Chương 0-4 chạy được trên CPU; từ chương 5 nên bật GPU.
import torch

device = 'cuda' if torch.cuda.is_available() else 'cpu'
print('device:', device)

Bật GPU đúng thì in cuda.

7

Hỏi nhanh

Trên Kaggle, mục Accelerator chỉ chọn được None. Lý do thường gặp nhất là gì?

8

Hỏi nhanh

Notebook có hai ô: trên là n = 3, dưới là total = sum(range(n + 1)). Hôm qua đã chạy cả hai. Hôm nay mở lại (kernel mới), chạy ô dưới trước. Ô dưới cho ra gì?

9

Chia số âm: khác C++

print(7 / 2, 6 / 2)
print(7 // 2, -7 // 2)
print(7 % 3, -7 % 3)
Kết quả3.5 3.0
3 -4
1 2

// làm tròn xuống. Với b≠0b\ne0:

a=(a//b)⋅b+(a%b).a=(a//b)\cdot b+(a\%b).

Số chia âm thì % không dương: 10 % -3 là −2-2.

int tăng độ chính xác theo nhu cầu; vẫn tốn thời gian và bộ nhớ khi số rất lớn.

10

Làm tròn xuống, không phải về 0

// làm tròn xuống; phép chia nguyên của C++ cắt về 0.7 / 2−5−4−3−2−10123453−7 / 2−5−4−3−2−1012345Python −4C++ −3
// làm tròn xuống; phép chia nguyên của C++ cắt về 0.
11

Hỏi nhanh

print(-7 // 2, -7 % 2) in ra gì?

12

Số thực cần kiểm sai số

import math
print(0.1 + 0.2, 0.1 + 0.2 == 0.3)
print(math.isclose(0.1 + 0.2, 0.3,
                   rel_tol=1e-9, abs_tol=1e-12))
print(round(2.5), round(3.5), round(0.125, 2))
Kết quả0.30000000000000004 False
True
2 4 0.12
  • 0.1 không lưu chính xác được trong nhị phân.
  • So số thực bằng math.isclose, không dùng ==.
  • round chọn mốc chẵn khi số nằm đúng giữa.
13

0.1 + 0.2 và 0.3 là hai số máy khác nhau

0.3 và 0.1 + 0.2 rơi vào hai số float64 liền kề.……0.30.299999999999999988900.1 + 0.20.30000000000000004441không có số float64 nào ở giữa
0.3 và 0.1 + 0.2 rơi vào hai số float64 liền kề.
14

Gán tên khác với sao chép

Gán chỉ dán thêm tên; copy() tạo list mới; int bất biến.b = ab.append(4)1234abc = a.copy()c.append(4)1231234acy = xy += 156xy
Gán chỉ dán thêm tên; copy() tạo list mới; int bất biến.
15

Sửa list, hay gán lại tên?

a = [1, 2, 3]
b = a
b.append(4)
print(a, b, a is b)
Kết quả[1, 2, 3, 4] [1, 2, 3, 4] True
  • append, a += [5]: sửa list chung.
  • a = a + [5]: tạo list mới, gán lại tên a.
  • is: cùng đối tượng? ==: giá trị bằng nhau?
16

Hỏi nhanh

def reset(scores):
    scores.append(0)
    scores = []
marks = [7, 8]
reset(marks)
print(marks)

Đoạn code in ra gì?

Phỏng theoNOAI 2026 Singapore · Vòng sơ loại · Câu 94

17

List lồng nhau: một hàng hay ba hàng?

grid = [[0] * 3] * 3
grid[0][0] = 9
print(grid)

grid = [[0] * 3 for _ in range(3)]
grid[0][0] = 9
print(grid)
Kết quả[[9, 0, 0], [9, 0, 0], [9, 0, 0]]
[[9, 0, 0], [0, 0, 0], [0, 0, 0]]

* 3 lặp lại tên của cùng một hàng, không tạo hàng mới.

Comprehension tạo một hàng mới ở mỗi lượt lặp.

copy() chỉ chép một tầng; deepcopy() chép mọi tầng.

18

Ba tên, một hàng

Gán 9 vào ô đầu: bên trái cả ba hàng đổi, bên phải chỉ một hàng đổi.[[0] * 3] * 3900[[0] * 3 for _ in range(3)]900000000
Gán 9 vào ô đầu: bên trái cả ba hàng đổi, bên phải chỉ một hàng đổi.
19

Hỏi nhanh

Chạy a = [[1, 2], [3, 4]], b = a.copy(), b[0].append(9). Lúc này a là gì?

20

Chọn cấu trúc như khi thi lập trình

Công việc Cấu trúc
Giữ thứ tự, lấy bằng vị trí list
Một bộ giá trị cố định tuple
Tra cứu theo khóa dict
Kiểm thuộc tập nhiều lần set

x in list: O(n)O(n) ở trường hợp xấu.

x in set: trung bình O(1)O(1), nhưng dựng set cũng tốn O(n)O(n).

Khóa của dict, phần tử của set phải hashable. (3, 4) được; list, hay tuple chứa list, thì không.

21

Đếm bằng dict

Đếm “mèo chó mèo gà mèo chó” bằng dict: mỗi từ chỉ chạm đúng một khóa, khóa mới bắt đầu từ 1.
22

Vì sao in trên set nhanh

List so từng phần tử; set nhảy thẳng tới một ngăn của bảng băm.99 in list162612547123455 lần so99 in set162612547hash(99) % 8 = 31 lần nhìn
List so từng phần tử; set nhảy thẳng tới một ngăn của bảng băm.
23

Hỏi nhanh

Có 50 000 mã đã nộp bài. Cần kiểm 10 000 mã khác xem đã nộp chưa. Nên làm thế nào?

24

Slicing, comprehension và vài hàm quen tay

a = [5, 3, 8, 1, 9, 2]
print(a[1:4], a[-1], a[-2:], a[::-1])
print([x * x for x in a if x % 2 == 1])
Kết quả[3, 8, 1] 2 [9, 2] [2, 9, 1, 8, 3, 5]
[25, 9, 1, 81]
  • enumerate: vị trí và phần tử.
  • zip: phần tử cùng vị trí của nhiều dãy.
  • sorted(..., key=...): sắp theo một giá trị.
  • d.get(key, default): xử lý khóa chưa có.
25

Tham số mặc định được tạo một lần

def add_score(x, history=[]):
    history.append(x)
    return history

print(add_score(1), add_score(2))
Kết quả[1, 2] [1, 2]

Hai lần gọi dùng chung list mặc định.

def add_score(x, history=None):
    if history is None:
        history = []
    history.append(x)
    return history
26

Một list mặc định cho mọi lần gọi

List mặc định tạo một lần và dùng chung; None cho mỗi lần gọi một list mới.history=[]add_score12add_score(1)add_score(2)history=Noneadd_score(1)1add_score(2)2
List mặc định tạo một lần và dùng chung; None cho mỗi lần gọi một list mới.
27

Hỏi nhanh

add_score(score, history=[]) gọi lần sau vẫn thấy điểm của lần trước. Sửa thế nào để mỗi lần gọi bắt đầu từ list rỗng?

28

Kiểm đáp án trước khi đo

Tổng 0+1+⋯+(n−1)0+1+\cdots+(n-1):

S=n(n−1)2.S=\frac{n(n-1)}{2}.

Với n=500 000n=500\,000: 124 999 750 000.

Ba cách: vòng for, sum(range(n)), NumPy. Cả ba phải ra đúng số này.

Rồi mới đo bằng timeit.repeat, mỗi cách chạy nhiều lần.

29

Vòng for chậm nhất

Cùng một tổng của 500 000 số, đo trên một máy CPU.for i in range(n): s += i17.04 mssum(range(n))6.63 msnp.arange(n).sum()0.26 ms05101520ms
Cùng một tổng của 500 000 số, đo trên một máy CPU.

sum và NumPy lặp bên trong code C nên nhanh hơn. Công thức n(n−1)/2n(n-1)/2 còn nhanh hơn cả ba.

30

Hỏi nhanh

Hai cách đều tính đúng. Cách A chạy 8 ms nhưng phải chuẩn bị dữ liệu thêm 5 ms. Cách B chạy 11 ms, không cần chuẩn bị. Chỉ chạy một lần thì cách nào nhanh hơn?

31

Ghi CSV rồi đọc lại

preds là dict ID → dự đoán.

with path.open(
    "w", newline="", encoding="utf-8"
) as file:
    writer = csv.writer(file)
    writer.writerow(["id", "prediction"])
    for student_id, prediction in preds.items():
        writer.writerow(
            [student_id, prediction]
        )
  • with đóng file khi ra khỏi khối.
  • Ghi rõ encoding="utf-8".
  • Đọc lại bằng csv.reader: mọi ô là chuỗi, đổi kiểu trước khi tính.
32

Hỏi nhanh

Đọc cột điểm bằng csv, ta được ["9", "10", "2"]. sorted trả về gì?

33

Đọc traceback từ dưới lên

Traceback thật của Python 3.13: đọc từ dòng cuối lên.Traceback (most recent call last): File "…/diem.py", line 7, in <module> print(mean_of("Dũng")) ~~~~~~~^^^^^^^^ File "…/diem.py", line 4, in mean_of marks = scores[name] ~~~~~~^^^^^^KeyError: 'Dũng'① lỗi gì② ở dòng nào③ ai đã gọiđọc từ dưới lên
Traceback thật của Python 3.13: đọc từ dòng cuối lên.
34

Bốn lỗi hay gặp

Bốn thông báo cuối của bốn traceback riêng:

Kết quảTypeError: can only concatenate str (not "int") to str
KeyError: 'Dũng'
IndexError: list index out of range
ValueError: invalid literal for int() with base 10: '7.5'
  • Dòng cuối: loại lỗi và nguyên nhân.
  • Các dòng File ..., line ...: vị trí cần mở code.
  • Không báo lỗi: kiểm kiểu, độ dài, vài giá trị.
35

Hỏi nhanh

marks có 3 phần tử. Vòng for i in range(1, len(marks) + 1): print(marks[i]) chạy ra sao?

Phỏng theoNOAI 2026 Singapore · Vòng sơ loại · Câu 137

36

Class: dữ liệu đi cùng hàm

class ScoreBook:
    def __init__(self, names, marks):
        self.names = list(names)
        self.marks = list(marks)

    def __len__(self):
        return len(self.marks)

    def __getitem__(self, i):
        return self.names[i], self.marks[i]
  • __init__ chạy khi tạo đối tượng; self là chính đối tượng.
  • len(book) gọi __len__, book[1] gọi __getitem__.
  • Class con gọi super().__init__(...) để chạy phần khởi tạo của cha.
  • Dataset và nn.Module ở chương 3 dùng đúng các hàm này.
37

Cú pháp và hàm đặc biệt

Ba cú pháp và hàm đặc biệt mà chúng gọi.viếtPython gọilen(ds)ds.__len__()Datasetds[i]ds.__getitem__(i)Datasetmodel(x)model.__call__(x)forward(x)nn.Module
Ba cú pháp và hàm đặc biệt mà chúng gọi.
38

Hỏi nhanh

Xóa dòng super().__init__(factor) trong ShiftScaler.__init__, rồi gọi ShiftScaler(2, 1)([1, 2, 3]). Điều gì xảy ra?

39

Khi đi thi

  • Restart & Run all trước khi nộp.
  • Nhiều số thì dùng sum hoặc NumPy.
  • encoding="utf-8", đọc lại file nộp.
02

Luyện đề

Luyện đề41

Luyện đề 1

Sau a = [1, 2], b = [1, 2], c = a, lệnh print(a == b, a is b, a is c) in ra gì?

Phỏng theoNOAI 2026 Singapore · Vòng sơ loại · Câu 95

Luyện đề42

Luyện đề 2

Quen C++, một bạn viết [1, 2] + [3, 4] để cộng từng phần tử. Python cho kết quả gì?

Đề thiNOAI 2026 Singapore · Vòng sơ loại · Câu 91

Luyện đề43

Luyện đề 3

Có words = ["mèo", "chó", "mèo"]. Cần gán cho mỗi từ khác nhau một số 0, 1,… Chạy lại lần nào cũng phải ra đúng một bảng. Viết thế nào?

Phỏng theoUSA-NA-AIO 2026 · Vòng 1 · Part 5.1-5.2

Luyện đề44

Chốt ý

//, % làm tròn xuống, khác C++ với số âm.

Gán không sao chép; cần list riêng thì copy().

Tính trên nhiều số thì dùng sum hoặc NumPy.

Luyện đề45

Sau giờ học

Làm 10 câu kiểm tra cuối bài trên trang bài học.

Chạy notebook: Restart & Run all, rồi thử đổi n mà không chạy lại ô dưới.