Mở đầu: Từ mảng động JavaScript đến Scripting trong AI
Đối với đa số lập trình viên phát triển web, JavaScript (JS) là ngôn ngữ thống trị tuyệt đối nhờ mô hình vạn vật bất đồng bộ dựa trên Event Loop và khả năng chạy trực tiếp trên trình duyệt. Tuy nhiên, khi bước chân vào lãnh địa của Trí Tuệ Nhân Tạo (AI) và Học Máy (Machine Learning), Python mới là tiêu chuẩn công nghiệp không thể chối cãi. Điều này dễ dẫn đến tâm lý e ngại vì phải làm quen với một cú pháp mới và cách quản lý công cụ hoàn toàn xa lạ.
Đừng lo lắng! Bài học này sẽ giúp bạn bắc một cây cầu tư duy vững chắc từ các khái niệm JS quen thuộc sang cú pháp tương đương của Python. Bạn sẽ thấy rằng việc học Python thực ra rất dễ dàng khi chúng ta đối chiếu trực tiếp các cấu trúc lệnh, cơ chế phân phối gói thư viện, và đặc biệt là cách xử lý vùng nhớ giữa hai ngôn ngữ. Nắm chắc bài học này sẽ giúp bạn tự tin viết các script đầu tiên và cấu hình môi trường sạch sẽ để huấn luyện AI.
1. Môi trường runtime: Python Interpreter vs Node.js
Điểm tương đồng lớn nhất giữa Python và JavaScript là cả hai đều là ngôn ngữ thông dịch (interpreted) với kiểu dữ liệu động (dynamic typing). Tuy nhiên, cơ chế thực thi bên dưới có những điểm khác biệt cốt lõi.
Trong khi Node.js sử dụng Engine V8 của Google để biên dịch mã JavaScript thành mã máy cục bộ thời gian
thực (JIT - Just-In-Time Compilation) giúp tối ưu hiệu năng I/O web thông qua việc dịch mã nguồn thành
bytecode (Ignition) rồi biên dịch thành mã máy tối ưu (TurboFan), thì trình thông dịch Python mặc định
(CPython) lại biên dịch mã nguồn thành bytecode trung gian (tệp tin .pyc trong thư mục
__pycache__) rồi thực thi tuần tự trên một máy ảo dựa trên ngăn xếp (Stack-based Virtual
Machine).
Python hy sinh một chút tốc độ thực thi thuần của CPU để đổi lấy sự đơn giản, khả năng viết mã cực kỳ ngắn gọn và tương thích cao với các thư viện viết bằng C/C++.
Tuy nhiên, tại sao Python vẫn thống trị mảng AI/Deep Learning vốn cực kỳ ngốn CPU/GPU? Đó là nhờ các thư viện tính toán tensor nền tảng như NumPy và PyTorch được viết bằng ngôn ngữ C++ và CUDA. Khi PyTorch thực hiện nhân ma trận, nó sẽ đẩy toàn bộ dữ liệu xuống tầng mã máy C++ chạy đa luồng bên ngoài sự quản lý của CPython Virtual Machine. Do đó, quá trình tính toán tính tensor hoàn toàn lách qua được khóa GIL của Python.
-
npm vs pip:
npm installtương đương vớipip install. Kho lưu trữ PyPI (Python Package Index) đóng vai trò tương tự npmjs.org. -
package.json vs requirements.txt: Thay vì liệt kê dependencies trong file JSON,
Python sử dụng file text đơn giản
requirements.txtchứa danh sách các thư viện kèm phiên bản (ví dụ:numpy==1.24.3). -
node_modules vs venv (Virtual Environment): Đây là điểm khác biệt lớn. Node.js tự
động tạo thư mục
node_modulescục bộ trong thư mục dự án để cô lập dependencies. Python thì mặc định cài đặt thư viện vào thư mục hệ thống toàn cục (global package). Để tránh xung đột phiên bản giữa các dự án khác nhau (dependency hell), bạn bắt buộc phải tạo môi trường ảo độc lập bằng công cụvenv.
Cơ chế của
venv chỉ đơn giản là tạo ra một bản sao gọn nhẹ của trình thông dịch Python và
sửa đổi các biến môi trường PATH và VIRTUAL_ENV của shell để trình thông dịch
ưu tiên tìm kiếm thư viện trong thư mục venv cục bộ của dự án trước (thay vì tìm trong
sys.path toàn cục).
Để khởi tạo một môi trường ảo cục bộ trong thư mục dự án của bạn (tương đương với việc có một thư mục cô lập dependencies riêng), hãy chạy các lệnh sau trong terminal:
# Tạo một môi trường ảo có tên là "venv" trong dự án
python3 -m venv venv
# Kích hoạt môi trường ảo trên macOS / Linux
source venv/bin/activate
# Kích hoạt môi trường ảo trên Windows (CMD)
# venv\Scripts\activate.bat
# Sau khi kích hoạt, bạn có thể cài đặt thư viện cục bộ mà không ảnh hưởng đến hệ thống
pip install numpy pandas
| Khái niệm | JavaScript (Node.js) | Python (CPython) |
|---|---|---|
| Quản lý thư viện | npm (Node Package Manager) | pip (Package Installer for Python) |
| Cô lập thư viện | node_modules (mặc định tạo cục bộ) | venv / conda (phải kích hoạt môi trường ảo chủ động) |
| Tệp khai báo thư viện | package.json | requirements.txt |
| Cơ chế thực thi | JIT Compilation (V8 Engine) | Interpreter / Bytecode VM |
2. Kiểu dữ liệu & Cơ chế tham chiếu qua lăng kính JS
Cú pháp dữ liệu của Python rất giống JavaScript, tuy nhiên Python phân biệt rạch ròi giữa các kiểu dữ liệu có thể thay đổi (Mutable) và không thể thay đổi (Immutable) ngay từ lõi thiết kế để tối ưu hóa hiệu năng bộ nhớ.
Trong JavaScript, bạn sử dụng Array và Object cho hầu hết cấu trúc dữ liệu. Ở
Python, các kiểu tương đương là:
- List (danh sách tuần tự): Tương đương mảng Array trong JS. Bản chất bên dưới của List là một mảng động (Dynamic Array) tự động mở rộng kích thước (over-allocation) khi đầy để tránh phải cấp phát bộ nhớ lại liên tục.
- Dict (Dictionary): Dạng bảng băm key-value, tương đương Object/Map của JS. Từ Python 3.6 trở đi, Dict được cấu trúc tối ưu hóa bộ nhớ và bảo toàn thứ tự chèn phần tử bằng cách sử dụng một mảng chỉ mục 1D gọn nhẹ song song với mảng lưu trữ giá trị thực.
-
Tuple: Một dạng danh sách cố định chỉ đọc (Immutable List) được bọc bởi dấu ngoặc đơn
(val1, val2). Tuple do tính bất biến nên có hiệu năng truy xuất nhanh hơn List và có thể được dùng làm khóa (key) trong Dict (vì giá trị của nó có mã hash cố định), điều mà List không làm được.
.map() hay .filter(), hệ
thống luôn khởi tạo một mảng mới trung gian hoàn toàn trên bộ nhớ RAM. Ở Python, ngoài List Comprehension
[x**2 for x in data] (tạo mảng mới), chúng ta có
Generator Expression bằng cách thay ngoặc vuông bằng ngoặc đơn:
(x**2 for x in data). Generator sử dụng cơ chế
đánh giá lười (Lazy Evaluation), chỉ tính toán giá trị tiếp theo khi được yêu cầu
(yield). Điều này giúp xử lý hàng triệu bản ghi dữ liệu mà không tốn thêm một byte RAM nào, cực kỳ tối
ưu cho các luồng nạp dữ liệu (data pipelines) của AI.
b = a rồi thay đổi giá trị trong
b, dẫn đến việc dữ liệu gốc trong a bị sửa đổi ngầm mà không hề biết.
Hãy xem ví dụ đối chiếu trực quan dưới đây để hiểu cách sao chép dữ liệu an toàn:
# ❌ SAI: Gán tham chiếu ngầm làm thay đổi cả danh sách gốc
list_a = [1, 2, 3]
list_b = list_a # Chỉ copy con trỏ địa chỉ vùng nhớ
list_b.append(4)
print(list_a) # Đầu ra: [1, 2, 3, 4] - dữ liệu gốc đã bị biến đổi!
# ✅ ĐÚNG: Sao chép nông (Shallow Copy) bằng phương thức .copy()
list_c = [1, 2, 3]
list_d = list_c.copy()
list_d.append(4)
print(list_c) # Đầu ra: [1, 2, 3] - danh sách gốc được an toàn!
Đối với các đối tượng từ điển phức tạp chứa nhiều tầng lồng nhau (nested dictionary), bạn bắt buộc phải sử
dụng thư viện chuẩn copy và hàm deepcopy() để nhân bản độc lập toàn bộ các vùng
nhớ con:
import copy
# Đối tượng dữ liệu lồng nhau
original = {"name": "AI Model", "layers": [128, 64, 32]}
# Thực hiện Deep Copy
cloned = copy.deepcopy(original)
cloned["layers"].append(16)
print(original["layers"]) # Đầu ra: [128, 64, 32] (Không bị thay đổi)
print(cloned["layers"]) # Đầu ra: [128, 64, 32, 16] (Đã được cập nhật riêng)
function f(arr = []) {"{"}...{"}"} được TẠO MỚI mỗi lần hàm được gọi. Trong Python, biểu
thức mặc định (def f(arr=[]):) chỉ được đánh giá ĐÚNG MỘT LẦN, tại thời
điểm hàm được định nghĩa — không phải mỗi lần gọi. Vì List là Mutable, mọi lần gọi hàm sau đó đều dùng
CHUNG một list đó, tích luỹ dữ liệu từ lần gọi trước.
# ❌ SAI: list mặc định bị "nhớ" giữa các lần gọi hàm khác nhau
def add_log(entry, history=[]):
history.append(entry)
return history
print(add_log("request-1")) # ['request-1'] — trông có vẻ ổn
print(add_log("request-2")) # ['request-1', 'request-2'] — SAI! Lẽ ra phải là ['request-2']
# history=[] chỉ được tạo 1 lần duy nhất khi def chạy, mọi lần gọi sau dùng chung 1 list
# ✅ ĐÚNG: dùng None làm giá trị mặc định, tạo list mới bên trong thân hàm
def add_log_fixed(entry, history=None):
if history is None:
history = [] # list mới tinh cho mỗi lần gọi
history.append(entry)
return history
print(add_log_fixed("request-1")) # ['request-1']
print(add_log_fixed("request-2")) # ['request-2'] — đúng, độc lập với lần gọi trước
Lỗi này đặc biệt nguy hiểm trong code xử lý dữ liệu AI vì nó thường "im lặng" — không ném exception nào cả, chỉ âm thầm tích luỹ dữ liệu rác qua nhiều lần gọi hàm (ví dụ một hàm tiền xử lý batch dữ liệu dùng list mặc định để "cache" kết quả tạm), khiến kết quả huấn luyện sai lệch mà rất khó truy ra nguyên nhân gốc.
3. Lập trình bất đồng bộ: Asyncio vs Event Loop
Trong JavaScript, lập trình bất đồng bộ (Asynchronous Programming) là cơ chế mặc định. Trình duyệt hoặc Node.js chạy một vòng lặp sự kiện (Event Loop) liên tục ở tầng nền để xử lý các sự kiện click, truy vấn mạng hoặc đọc file không chặn (non-blocking) thông qua Call Stack, Microtask Queue (Promises) và Macrotask Queue.
Trái lại, Python về bản chất là ngôn ngữ đồng bộ tuần tự (Synchronous - Blocking). Khi chạy phép toán
nặng, luồng bị chặn hoàn toàn. Để chạy bất đồng bộ, Python giới thiệu thư viện chuẩn
asyncio dựa trên coroutine. Điểm khác biệt mấu chốt là:
Vòng lặp sự kiện trong Python không tự chạy ngầm. Bạn phải tự khởi động và đăng ký hàm
bất đồng bộ đầu tiên vào Event Loop một cách chủ động thông qua lệnh asyncio.run().
time.sleep(5)) bên trong một hàm async của Python, toàn bộ Event Loop của
asyncio sẽ bị treo cứng. Mọi tác vụ async chạy song song khác sẽ bị đóng băng. Để tránh điều này, bạn
phải sử dụng các thư viện async tương thích (như aiohttp cho mạng), hoặc chuyển tác vụ nặng
sang chạy ở thread riêng biệt.
Cách khắc phục cụ thể (từ Python 3.9 trở lên): dùng asyncio.to_thread() để đẩy hàm chặn luồng
sang một thread nền, giải phóng Event Loop tiếp tục xử lý các tác vụ async khác trong lúc chờ:
import asyncio
import time
def cpu_heavy_task():
time.sleep(3) # Giả lập tác vụ CPU nặng/blocking I/O cũ chưa hỗ trợ async
return "Xong việc nặng"
async def ticker():
for i in range(5):
print(f"Tick {i} — Event Loop vẫn đang chạy...")
await asyncio.sleep(0.5)
async def main():
# ❌ Nếu gọi cpu_heavy_task() trực tiếp ở đây, ticker() sẽ bị đóng băng 3 giây.
# ✅ Đẩy sang thread riêng, Event Loop rảnh để chạy song song ticker() bên dưới:
result_task = asyncio.create_task(asyncio.to_thread(cpu_heavy_task))
ticker_task = asyncio.create_task(ticker())
result = await result_task
print(result)
await ticker_task
asyncio.run(main())
# Kết quả: "Tick 0..4" vẫn in đều đặn mỗi 0.5s trong lúc cpu_heavy_task() chạy ngầm 3s
Hãy cùng so sánh cấu trúc mã viết async/await giữa JavaScript và Python:
// Phiên bản JavaScript (Node.js)
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
async function fetchMetadata() {
console.log("Bắt đầu tải...");
await delay(1000); // Chờ không chặn
console.log("Hoàn thành tải.");
return { status: 200 };
}
// Chạy trực tiếp, Event Loop của JS tự động xử lý ngầm
fetchMetadata();
# Phiên bản Python (asyncio)
import asyncio
async def fetch_metadata():
print("Bắt đầu tải...")
await asyncio.sleep(1) # Chờ không chặn tương đương delay
print("Hoàn thành tải.")
return {"status": 200}
# Bắt buộc phải khởi động Event Loop thủ công
result = asyncio.run(fetch_metadata())
4. Dự án thực hành: Công cụ thu thập và chuẩn hóa dữ liệu thô
Để biến lý thuyết thành thực tiễn, chúng ta sẽ xây dựng một script Python hoàn chỉnh chạy trong môi trường
ảo venv. Script này sẽ thực hiện đọc một tệp tin dữ liệu dạng JSON giả lập chứa danh sách các
phản hồi thô từ người dùng, loại bỏ các khoảng trắng dư thừa, làm sạch văn bản viết thường và lưu kết quả
sạch thành tệp tin CSV để sẵn sàng đưa vào các mô hình xử lý ngôn ngữ tự nhiên (NLP) ở các bài học sau.
import json
import csv
import os
def clean_text(text):
"""
Hàm làm sạch văn bản cơ bản
"""
if not isinstance(text, str):
return ""
# Loại bỏ khoảng trắng thừa đầu cuối và chuyển về dạng viết thường
return text.strip().lower()
def run_cleaning_pipeline(input_path, output_path):
print("--- Bắt đầu quy trình xử lý dữ liệu ---")
# Kiểm tra tệp tin đầu vào có tồn tại không
if not os.path.exists(input_path):
print(f"Lỗi: Tệp {input_path} không tồn tại.")
return
# Đọc dữ liệu JSON thô
with open(input_path, "r", encoding="utf-8") as file:
raw_data = json.load(file)
cleaned_records = []
# Lặp qua từng bản ghi dữ liệu bằng vòng lặp Python
for index, record in enumerate(raw_data):
user_id = record.get("id", index)
raw_comment = record.get("comment", "")
# Gọi hàm làm sạch
clean_comment = clean_text(raw_comment)
cleaned_records.append({
"user_id": user_id,
"cleaned_comment": clean_comment
})
# Ghi dữ liệu sạch ra tệp CSV để huấn luyện mô hình
with open(output_path, "w", newline="", encoding="utf-8") as csv_file:
fieldnames = ["user_id", "cleaned_comment"]
writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
# Ghi tiêu đề cột
writer.writeheader()
# Ghi các dòng dữ liệu
writer.writerows(cleaned_records)
print(f"Xử lý thành công! Đã ghi nhận {len(cleaned_records)} bản ghi sạch vào {output_path}")
# Kiểm thử quy trình chạy
if __name__ == "__main__":
# Tạo tệp JSON mẫu để test
mock_data = [
{"id": 101, "comment": " Mô hình AI chạy RẤT NHANH! "},
{"id": 102, "comment": "Tôi Cần hỗ Trợ kỹ thuật gấp... "},
{"id": 103, "comment": " Tuyệt VỜI, 10 điểm. "}
]
with open("raw_feedback.json", "w", encoding="utf-8") as f:
json.dump(mock_data, f, ensure_ascii=False, indent=2)
# Chạy pipeline làm sạch dữ liệu
run_cleaning_pipeline("raw_feedback.json", "cleaned_feedback.csv")
Để chạy dự án thực hành này trên máy tính của bạn, hãy thực hiện theo đúng các bước quy chuẩn sau:
-
Mở terminal tại thư mục chứa file code và khởi tạo môi trường ảo:
python3 -m venv venv. -
Kích hoạt môi trường ảo:
source venv/bin/activate(đối với macOS/Linux) hoặcvenv\Scripts\activate(đối với Windows). - Chạy script Python:
python data_cleaner.py. -
Kiểm tra thư mục dự án, bạn sẽ thấy tệp
raw_feedback.jsonđược sinh ra tự động và tệp kết quả sạchcleaned_feedback.csvchứa các bình luận đã được định dạng chuẩn viết thường và loại bỏ khoảng trắng thừa hoàn hảo.
Tóm tắt bài học & Cầu nối kiến thức
- Đạt được: Làm chủ cú pháp Python cơ bản và sự khác biệt về kiểu dữ liệu so với JavaScript.
-
Đạt được: Biết cách thiết lập môi trường ảo
venvvà quản lý thư viện bằngpipthay thế chonpm/node_modules.
Cầu nối bài tiếp theo: Có được tư duy viết mã Python, bài học tiếp theo sẽ đưa ta bước vào thế giới toán học nền tảng của Trí tuệ nhân tạo: các phép toán Vector, Ma trận và Đạo hàm được lập trình trực quan bằng Python thuần túy.
Tải file code thực hành minh họa bài học
File Python data_cleaner.py — script xử lý và chuẩn hóa dữ liệu mẫu dùng trong bài học này
(chạy python data_cleaner.py, không cần cài thêm gì):
Bình luận