Giao diện
1. Phím tắt dòng lệnh tương tác trong IPython
Sau khi một hàm xử lý dữ liệu báo lỗi, bạn muốn xem biến ở bước sai và thử lại một phần của chương trình. IPython hỗ trợ gỡ lỗi sau ngoại lệ, xem lịch sử, chạy tệp và đo thời gian ngay trong phiên tương tác. Các công cụ này giúp thử một giả thuyết cụ thể về lỗi hoặc hiệu năng mà không phải viết lại chương trình kiểm tra từ đầu.
Phím tắt phụ thuộc terminal, chế độ sửa dòng và cấu hình. IPython hiện dùng prompt_toolkit với nhiều tổ hợp kiểu Readline. Các tổ hợp dưới đây là điểm bắt đầu để tra cứu, không phải hành vi cố định trên mọi môi trường.
1.1. Điều hướng con trỏ
Ctrl + A: Di chuyển con trỏ về ngay đầu dòng lệnh.Ctrl + E: Di chuyển con trỏ tới cuối dòng lệnh.Ctrl + B: Di chuyển con trỏ lùi lại một ký tự (tương đương phím mũi tên trái).Ctrl + F: Di chuyển con trỏ tiến lên một ký tự (tương đương phím mũi tên phải).
1.2. Xóa và chỉnh sửa văn bản
Ctrl + K: Xóa toàn bộ văn bản từ vị trí con trỏ hiện tại tới cuối dòng.Ctrl + U: Xóa toàn bộ văn bản từ đầu dòng tới vị trí con trỏ hiện tại.Ctrl + W: Xóa một từ nằm ngay trước con trỏ.Ctrl + Y: Dán lại (yank) đoạn văn bản vừa bị xóa bằng các lệnh trên.
1.3. Điều khiển và tìm kiếm lịch sử
Ctrl + R: Kích hoạt chế độ tìm kiếm tăng dần trong lịch sử lệnh. Nhập từ khóa để tự động khớp lại các câu lệnh phức tạp đã từng thực thi trước đó.Ctrl + L: Xóa sạch màn hình dòng lệnh và vẽ lại dấu nhắc hiện tại ở dòng đầu tiên.Ctrl + C: Ngắt tiến trình Python đang chạy, gửi tín hiệu ngắtKeyboardInterrupt.
2. Hệ thống lệnh ma thuật
Lệnh ma thuật là các lệnh đặc biệt bắt đầu bằng ký tự phần trăm %, cung cấp các tiện ích điều khiển hệ thống mà cú pháp Python tiêu chuẩn không hỗ trợ. IPython phân biệt hai loại lệnh ma thuật:
- Ma thuật dòng (Line Magics): Bắt đầu bằng một ký tự
%, chỉ nhận đối số nằm trên cùng một dòng lệnh. - Ma thuật ô (Cell Magics): Bắt đầu bằng hai ký tự
%%, áp dụng lên toàn bộ khối mã của một ô trong Jupyter Notebook.
2.1. Lệnh %run thực thi tệp kịch bản
Lệnh %run <ten_tep.py> thực thi trực tiếp tệp mã nguồn Python bên trong phiên làm việc của IPython:
ipython
%run thong_ke_doanh_thu.pyKhác với việc chạy python thong_ke_doanh_thu.py từ terminal ngoài, lệnh %run bảo lưu toàn bộ các biến, hàm và đối tượng vừa được định nghĩa trong tệp vào không gian tên hiện tại của IPython. Nhờ đó, sau khi chạy kịch bản, bạn có thể kiểm tra ngay giá trị của các biến trong RAM hoặc gọi tiếp các hàm mà không cần nạp lại dữ liệu.
2.2. Dán mã nguồn với %paste và %cpaste
Khi sao chép mã nguồn từ các trang web hoặc tài liệu có nhiều cấp thụt lề phức tạp, việc dán trực tiếp vào terminal thông thường có thể khiến trình thông dịch hiểu nhầm dấu cách và báo lỗi cú pháp.
%paste: Tự động lấy văn bản từ clipboard của hệ điều hành, chuẩn hóa lại thụt lề và thực thi an toàn.%cpaste: Mở ra một vùng nhập liệu đặc biệt, cho phép dán nhiều đoạn mã liên tiếp, kiểm tra kỹ lưỡng trước khi gõ--để thực thi.
2.3. Tra cứu nhanh với %magic và %quickref
%magic: Hiển thị toàn bộ tài liệu hướng dẫn chi tiết về mọi lệnh ma thuật có sẵn trong IPython.%quickref: Bảng tra cứu tóm tắt các cú pháp dòng lệnh, phím tắt và tiện ích thường dùng nhất.
3. Quản lý lịch sử lệnh và biến đầu vào đầu ra
IPython duy trì một cơ chế ghi nhận nhật ký toàn diện cho toàn bộ các biểu thức được thực thi trong một phiên làm việc.
3.1. Các biến đặc biệt _ và __
- Ký tự gạch dưới đơn
_: Lưu trữ giá trị của kết quả đầu ra gần đây nhất. - Ký tự gạch dưới kép
__: Lưu trữ giá trị của kết quả đầu ra trước đó hai bước.
text
In [1]: 150000 * 4
Out[1]: 600000
In [2]: _ + 50000
Out[2]: 6500003.2. Danh sách In và từ điển Out
Mỗi lượt tương tác được đánh số thứ tự
_i<n>hoặcIn[n]: Lưu chuỗi mã nguồn đầu vào của lượt thực thi thứ. _o<n>hoặcOut[n]: Lưu trữ đối tượng kết quả trả về của biểu thức ở lượt thực thi thứ.
Lưu ý: Chỉ những biểu thức có sinh ra giá trị đầu ra (như phép tính, lời gọi hàm trả về dữ liệu) mới được lưu vào Out. Các câu lệnh không trả về giá trị (như x = 10 hoặc lệnh print()) sẽ không có mục tương ứng trong Out.
3.3. Xem lịch sử với %history
Lệnh %history cho phép xem lại các câu lệnh đã chạy:
ipython
%history -n 1-5 # In lại các câu lệnh từ lượt 1 đến lượt 5 kèm số thứ tự4. Tương tác trực tiếp với hệ điều hành
IPython cho phép điều phối các công cụ của hệ điều hành ngay trong luồng làm việc phân tích dữ liệu mà không cần chuyển đổi cửa sổ terminal.
4.1. Thực thi lệnh hệ vỏ với tiền tố !
Đặt dấu chấm than ! ở đầu dòng để gọi bất kỳ tiện ích hệ vỏ nào:
ipython
# Xem danh sách tệp tin trong thư mục
!dir # Trên Windows
!ls -la # Trên Linux/macOS
# Kiểm tra trạng thái Git
!git statusIPython cho phép bắt đầu ra của lệnh hệ vỏ vào một biến Python:
ipython
danh_sach_tep = !dir /b
print(f"Số lượng tệp: {len(danh_sach_tep)}")Biến danh_sach_tep là một đối tượng danh sách đặc biệt của IPython, cho phép bạn lặp và lọc các tệp bằng cú pháp Python.
4.2. Điều hướng thư mục với %pwd, %cd và %dhist
%pwd: In ra đường dẫn của thư mục làm việc hiện hành (print working directory).%cd <duong_dan>: Chuyển đổi thư mục làm việc hiện tại.%dhist: In ra toàn bộ lịch sử các thư mục mà phiên làm việc đã từng điều hướng qua.
4.3. Hệ thống đánh dấu thư mục với %bookmark
Khi thường xuyên phải làm việc với các đường dẫn thư mục sâu trong ổ đĩa, bạn có thể tạo các điểm đánh dấu ghi nhớ:
ipython
# Tạo điểm đánh dấu mang tên 'duan'
%bookmark duan C:\Users\Ai\Projects\DataProcessing
# Chuyển nhanh tới thư mục đã đánh dấu từ bất kỳ đâu
%cd duan5. Công cụ gỡ lỗi và đo lường hiệu năng
5.1. Trình gỡ lỗi tương tác sau sự cố
Khi một câu lệnh hoặc kịch bản chạy bị sập do phát sinh ngoại lệ đột ngột, việc gõ lệnh %debug ngay sau đó sẽ kích hoạt trình gỡ lỗi tương tác:
ipython
%debugIPython sẽ tự động đưa con trỏ gỡ lỗi tới đúng dòng mã phát sinh ngoại lệ, hiển thị khung ngăn xếp (stack frame) và mở dấu nhắc ipdb>.
Các lệnh điều khiển cơ bản trong ipdb:
p <ten_bien>: In giá trị hiện tại của biến tại thời điểm gặp lỗi.u(up): Di chuyển lên một cấp khung ngăn xếp gọi hàm bên ngoài.d(down): Di chuyển xuống một cấp khung ngăn xếp bên trong.n(next): Thực thi dòng lệnh kế tiếp.s(step): Nhảy vào bên trong hàm đang được gọi.c(continue): Tiếp tục thực thi chương trình cho tới điểm dừng tiếp theo.q(quit): Thoát khỏi trình gỡ lỗi.
Ngoài ra, bạn có thể đặt điểm dừng chủ động trong mã nguồn bằng hàm tích hợp sẵn của Python: breakpoint().
5.2. Đo lường thời gian thực thi với %time và %timeit
%time: Đo thời gian thực thi một lần duy nhất của câu lệnh. Báo cáo cung cấp hai thông số:CPU times: Thời gian vi xử lý thực sự dành để tính toán mã lệnh.Wall time: Thời gian thực tế trôi qua theo đồng hồ treo tường (bao gồm cả thời gian chờ đọc đĩa, mạng và chuyển ngữ cảnh của hệ điều hành).
%timeit: Công cụ đo lường hiệu năng chuyên nghiệp.%timeittự động thực thi câu lệnh lặp đi lặp lại hàng trăm đến hàng triệu lần, tính toán thời gian trung bình và độ lệch chuẩn của phép đo. Nó tự động vô hiệu hóa cơ chế dọn rác tạm thời để hạn chế tối đa nhiễu đo lường:
ipython
%timeit [x**2 for x in range(1000)]
# 52.3 µs ± 1.1 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)5.3. Đo đạc hiệu năng hàm với %prun
Khi một chương trình chạy chậm, việc đoán mò nguyên nhân thường dẫn đến tối ưu hóa sai chỗ. Lệnh ma thuật %prun sử dụng mô-đun cProfile để đo đạc chính xác thời gian tiêu tốn trong từng hàm:
ipython
%prun ham_xu_ly_du_lieu(bang)Bảng kết quả thống kê các cột:
ncalls: Số lần hàm được gọi.tottime: Tổng thời gian thực thi bên trong bản thân hàm đó (không tính thời gian gọi các hàm con).percall: Thời gian trung bình cho mỗi lần gọi hàm (tottime / ncalls).cumtime: Thời gian tích lũy tiêu tốn trong hàm đó và toàn bộ các hàm con mà nó gọi.
5.4. Đo đạc hiệu năng từng dòng lệnh với %lprun
Để biết chính xác dòng lệnh nào trong một hàm chiếm nhiều thời gian nhất, ta sử dụng thư viện line_profiler qua lệnh ma thuật %lprun:
ipython
# Nạp tiện ích mở rộng line_profiler
%load_ext line_profiler
# Đo đạc chi tiết từng dòng của hàm xu_ly
%lprun -f xu_ly xu_ly(du_lieu)Bảng báo cáo sẽ in ra tỷ lệ phần trăm thời gian % Time trên từng dòng mã, giúp người kỹ sư phát hiện ngay các phép toán tạo bản sao ngầm hoặc các vòng lặp thừa thãi.
6. Bí quyết lập trình hiệu quả với IPython
6.1. Tự động nạp lại mô-đun phụ thuộc với %autoreload
Một vấn đề nan giải khi phát triển mã nguồn: Bạn vừa viết sổ tay vừa chỉnh sửa các hàm trong tệp thư viện .py bên cạnh. Khi bạn sửa tệp .py và gõ lại import my_module, Python sẽ bỏ qua vì mô-đun đã nằm trong bộ nhớ đệm sys.modules.
Tiện ích mở rộng autoreload giải quyết triệt để vấn đề này:
ipython
%load_ext autoreload
%autoreload 2Với thiết lập %autoreload 2, mỗi khi bạn thực thi một câu lệnh mới trong IPython, hệ thống sẽ tự động quét và nạp lại toàn bộ các mô-đun .py đã bị sửa đổi trên đĩa trước khi chạy lệnh. Bạn không bao giờ phải khởi động lại kernel chỉ để cập nhật một dòng sửa đổi trong thư viện.
6.2. Nguyên tắc thiết kế mã nguồn tương tác
- Duy trì các đối tượng dữ liệu lớn thường trực trong RAM: Khi làm việc với tập dữ liệu hàng triệu bản ghi, việc đọc tệp từ đĩa có thể mất vài phút. Hãy thiết kế quy trình nạp dữ liệu ở một ô riêng biệt. Toàn bộ các phép thử nghiệm thuật toán và vẽ biểu đồ được thực hiện trên các ô bên dưới, tái sử dụng trực tiếp đối tượng bảng trong RAM.
- Ưu tiên cấu trúc hàm phẳng (Flat is better than nested): Tránh lồng các hàm quá sâu bên trong nhau. Tách các bước biến đổi thành các hàm độc lập cấp mô-đun giúp bạn dễ dàng gọi trực tiếp từng hàm con từ cửa sổ IPython để truyền dữ liệu mẫu và kiểm tra biên.
- Không e ngại các tệp mã nguồn dài hơn: Trong giai đoạn phát triển, gom nhóm các hàm liên quan chặt chẽ vào cùng một tệp giúp tìm kiếm và quản lý phụ thuộc trực quan hơn. Việc chia nhỏ thành quá nhiều tệp ngắn thường làm tăng độ phức tạp khi điều hướng mã nguồn.
7. Cấu hình nâng cao và hồ sơ IPython
Mọi hành vi mặc định của IPython có thể được tùy biến thông qua hệ thống hồ sơ cấu hình:
7.1. Khởi tạo hồ sơ mặc định
Chạy lệnh từ terminal để sinh tệp cấu hình chuẩn:
bash
ipython profile createLệnh này tạo ra thư mục cấu hình tại ~/.ipython/profile_default/, chứa tệp cấu hình chính ipython_config.py.
7.2. Tự động thực thi kịch bản khi khởi động
Thư mục ~/.ipython/profile_default/startup/ chứa các kịch bản Python sẽ được tự động thực thi theo thứ tự tên tệp mỗi khi một phiên IPython khởi động.
Bạn có thể tạo tệp 00-first.py trong thư mục trên với nội dung:
python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# Cấu hình chỉ chạy khi đang ở trong IPython.
from IPython import get_ipython
shell = get_ipython()
if shell is not None:
shell.run_line_magic("load_ext", "autoreload")
shell.run_line_magic("autoreload", "2")Mỗi khi bạn mở IPython hoặc Jupyter Notebook, các thư viện np, pd, plt và tiện ích autoreload đều đã sẵn sàng mà không cần gõ lại các lệnh nhập thủ công.
Tài liệu tham khảo
- Wes McKinney. Python for Data Analysis: Data Wrangling with pandas, NumPy, and Jupyter, tái bản lần 3. O'Reilly Media, 2022. Phụ lục B: More on the IPython System.
- Fernando Pérez, Brian E. Granger. IPython: A System for Interactive Scientific Computing. Computing in Science & Engineering, 2007.
- IPython Development Team. IPython Interactive Computing Documentation. https://ipython.readthedocs.io/
8. Bài tập thực hành
Bài tập 1: Đo lường và so sánh hiệu năng giữa thuật toán thuần và thư viện bằng %timeit
Một bài toán yêu cầu tính tổng bình phương của
- Hãy viết biểu thức tính toán bằng Python thuần sử dụng hàm
sum()kết hợp với biểu thức sinh (generator expression). - Hãy viết biểu thức tính toán sử dụng mảng NumPy và hàm
np.sum(). - Với
, kiểm chứng hai cách tính bằng công thức tổng bình phương: - Dùng lệnh ma thuật
%timeitđể đo thời gian thực thi của cả hai phương pháp và nhận xét về sự chênh lệch hiệu năng.
Lời giải
python
import numpy as np
n = 100_000
arr = np.arange(n, dtype=np.int64)
# 1. Python thuần với generator
tong_py = sum(x**2 for x in range(n))
# 2. NumPy vector hóa
tong_np = np.sum(arr**2)
# 3. Kiểm chứng bằng công thức toán học giải tích
tong_giai_tich = (n - 1) * n * (2 * n - 1) // 6
assert tong_py == tong_np == tong_giai_tich
print(f"Tổng bình phương tính toán: {tong_np:,}")
# 4. Đo đạc thời gian bằng %timeit trong IPython
# %timeit sum(x**2 for x in range(n))
# %timeit np.sum(arr**2)Kết quả đo lường thực tế trên máy tính:
- Python thuần: Tiêu tốn khoảng
cho mỗi lượt tính do phải duyệt qua số nguyên và thực hiện phép nhân mũ trong máy ảo. - NumPy vector hóa: Tiêu tốn khoảng
( ). - Nhận xét: Phiên bản vector hóa của NumPy nhanh hơn khoảng
lần so với Python thuần, chứng minh sự vượt trội của việc xử lý dữ liệu số học trong vùng nhớ liên tục được tối ưu hóa phần cứng.
Bài tập 2: Tự động hóa trích xuất kết quả từ lịch sử In và Out
Trong một phiên làm việc khám phá dữ liệu, người phân tích đã chạy các câu lệnh tính toán sau:
- Lượt 1: Khởi tạo biến dữ liệu doanh thu.
- Lượt 2: Tính doanh thu trung bình.
- Lượt 3: Tính độ lệch chuẩn.
- Hãy giải thích cơ chế lưu trữ của danh sách
Invà từ điểnOuttrong IPython. - Giả sử tại lượt thứ 4, người phân tích muốn tính hệ số biến thiên (Coefficient of Variation - CV), định nghĩa bằng tỉ số giữa độ lệch chuẩn (tính ở lượt 3) và trung bình (tính ở lượt 2):Hãy viết biểu thức trích xuất giá trị từ
Outđể tính toán chỉ số trên mà không cần thực thi lại mã nguồn của lượt 2 và lượt 3. - Khi nào một câu lệnh trong
Inkhông có giá trị tương ứng trongOut? Cho ví dụ cụ thể.
Lời giải
- Cơ chế lưu trữ của
InvàOut:Inlà một danh sách các chuỗi văn bản (listofstr). Mỗi phần tửIn[n]lưu trữ nguyên vẹn đoạn mã nguồn mà người dùng đã nhập ở lượt thứ. Outlà một từ điển (dict). Mỗi mụcOut[n]lưu trữ đối tượng Python thực tế là kết quả của biểu thức được đánh giá ở lượt thứ.
- Tính toán hệ số biến thiên sử dụng từ điển
Out:
python
# Mô phỏng trạng thái lịch sử
In = ["", "du_lieu = [10, 20, 30, 40, 50]", "np.mean(du_lieu)", "np.std(du_lieu)"]
Out = {2: 30.0, 3: 14.142135623730951}
# Tính hệ số biến thiên CV từ lịch sử Out
cv = Out[3] / Out[2]
print(f"Hệ số biến thiên CV: {cv:.4f}") # 0.4714Biểu thức này lấy trực tiếp hai con số đã tính toán trong RAM mà không cần duyệt lại tập dữ liệu du_lieu. 3. Câu lệnh không có kết quả trong Out:
- Mọi câu lệnh gán biến (như
x = 100), câu lệnh điều khiển (nhưfor,if), định nghĩa hàm (def), hoặc hàm trả vềNone(chẳng hạnprint("Xin chào")) đều không sinh ra giá trị đầu ra. Do đó, các lượt chạy này chỉ được ghi nhận trong danh sáchInmà hoàn toàn vắng mặt trong từ điểnOut.
Bài tập 3: Mô phỏng phân tích hiệu năng từng dòng để xác định điểm nghẽn
Cho hàm làm sạch dữ liệu chuỗi thô sau:
python
import re
def lam_sach_du_lieu(danh_sach_ban_ghi):
ket_qua = []
for ban_ghi in danh_sach_ban_ghi:
s = ban_ghi.strip()
if s != "N/A":
so_thuc = float(s)
ket_qua.append(so_thuc)
return ket_qua- Phân tích chức năng của từng dòng mã trong hàm trên.
- Dữ liệu thử nghiệm gồm các bản ghi:
[" 100.5 ", " 200.75 ", " N/A ", " 300.0 "]. Hãy chạy hàm và tính tổng các số thu được. - Trong các dòng mã bên trong vòng lặp, dòng lệnh nào có khả năng tiêu tốn nhiều thời gian nhất khi xử lý hàng triệu bản ghi? Đề xuất phương án tối ưu hóa hiệu năng nếu dữ liệu có thể chuyển đổi thành mảng pandas hoặc NumPy.
Lời giải
- Phân tích chức năng:
s = ban_ghi.strip(): Loại bỏ các khoảng trắng thừa ở hai đầu chuỗi ký tự.if s != "N/A": Kiểm tra giá trị chuỗi có phải là chuỗi đánh dấu khuyết thiếu hay không.so_thuc = float(s): Ép kiểu chuỗi ký tự sang số thực dấu phẩy động.ket_qua.append(so_thuc): Thêm số thực hợp lệ vào danh sách kết quả.
- Chạy thử nghiệm và kiểm chứng:
python
ban_ghi_mau = [" 100.5 ", " 200.75 ", " N/A ", " 300.0 "]
du_lieu_sach = lam_sach_du_lieu(ban_ghi_mau)
assert du_lieu_sach == [100.5, 200.75, 300.0]
tong_gia_tri = sum(du_lieu_sach)
print(f"Tổng giá trị hợp lệ: {tong_gia_tri}") # 601.25- Đánh giá hiệu năng và tối ưu hóa:
- Khi xử lý hàng triệu bản ghi, thao tác
float(s)vàban_ghi.strip()trên từng đối tượng chuỗi Python thông dịch chiếm phần lớn thời gian (thường chiếm trêntổng thời gian hàm theo báo cáo %lprun). - Phương án tối ưu hóa: Chuyển toàn bộ danh sách chuỗi thô thành một đối tượng
Seriescủa pandas và sử dụng hàm vector hóa chuyên dụngpd.to_numeric(s.str.strip(), errors="coerce"). Cách làm này đẩy toàn bộ vòng lặp phân tích chuỗi xuống tầng C, tự động chuyển đổi các giá trị"N/A"thànhNaNvà tăng tốc độ xử lý lên từ 10 đến 50 lần.
- Khi xử lý hàng triệu bản ghi, thao tác
Tài liệu tham khảo
- Wes McKinney. Python for Data Analysis: Data Wrangling with pandas, NumPy, and Jupyter, tái bản lần 3. O'Reilly Media, 2022. Phụ lục B: More on the IPython System.
- Fernando Pérez, Brian E. Granger. IPython: A System for Interactive Scientific Computing. Computing in Science & Engineering, 2007.
- IPython Development Team. IPython Interactive Computing Documentation. https://ipython.readthedocs.io/