Uploaded by trongbinhspk

gt lap trinh python can ban ebook

advertisement
TRẦN NHẬT QUANG
PHẠM VĂN KHOA
GIÁO TRÌNH
LẬP TRÌNH PYTHON CĂN BẢN
NHAØ XUAÁT BAÛN
ÑAÏI HOÏC QUOÁC GIA TP. HOÀ CHÍ MINH
TS. TRẦN NHẬT QUANG, TS. PHẠM VĂN KHOA
GIÁO TRÌNH
LẬP TRÌNH
PYTHON CĂN BẢN
NHÀ XUẤT BẢN ĐẠI HỌC QUỐC GIA
THÀNH PHỐ HỒ CHÍ MINH – 2023
2
LỜI NÓI ĐẦU
Python hiện là ngôn ngữ lập trình phổ biến nhất thế giới1. Ưu điểm nổi bật
của Python là dễ học, dễ viết. Không những thế, Python còn có một cộng
đồng người dùng lớn và hệ thống thư viện mã nguồn mở đồ sộ giúp bạn
hoàn thành các dự án của mình nhanh chóng và hiệu quả. Cho dù đó là một
dự án về phân tích dữ liệu, học máy, xử lý ảnh, game, điều khiển thiết bị,
hoặc chỉ đơn giản là tự động hóa các tác vụ trên máy tính của bạn, thì gần
như bạn đều có thể tìm thấy các thư viện Python hỗ trợ.
Quyển giáo trình này được biên soạn với mong muốn hỗ trợ hiệu quả cho
các bạn sinh viên học lập trình Python. Tiêu chí thứ nhất của nhóm biên
soạn là giúp người học lập trình lần đầu cũng có thể dễ dàng nắm bắt
được các khái niệm và kỹ thuật lập trình với Python. Tiêu chí thứ hai là cố
gắng trình bày nội dung một cách súc tích, nhưng vẫn đầy đủ, để những
bạn đã học qua lập trình có thể nhanh chóng làm quen và sử dụng được
Python khi học xong giáo trình.
Rất mong quyển giáo trình này sẽ hữu ích với các bạn! Nhóm biên soạn
cũng mong nhận được góp ý của độc giả để cải thiện giáo trình này ngày
càng tốt hơn. Xin cảm ơn các bạn!
1
Theo xếp hạng của TIOBE Index và PYPL Index cập nhật vào tháng 3 năm 2022.
3
4
MỤC LỤC
LỜI NÓI ĐẦU .......................................................................................... 3
MỤC LỤC ................................................................................................ 5
DANH MỤC HÌNH ẢNH ......................................................................... 8
Chương 1 GIỚI THIỆU VÀ CÀI ĐẶT PYTHON .................................. 9
1.1 Đôi nét về ngôn ngữ lập trình Python ............................................ 9
1.2 Lịch sử phát triển Python ............................................................. 10
1.3 Cài đặt Python .............................................................................. 11
1.4 Một số lời khuyên hữu ích cho những người mới ...................... 16
Chương 2 PHÉP TOÁN CƠ BẢN, BIẾN VÀ NHẬP XUẤT TRONG
PYTHON .............................................................................................. 18
2.1 Sử dụng VS Code như một máy tính cầm tay.............................. 18
2.2 Các phép toán ............................................................................... 19
2.3 Biến .............................................................................................. 21
2.4 Nhập xuất cơ bản ......................................................................... 23
2.5 Lệnh if .......................................................................................... 26
Bài tập có lời giải ................................................................................. 32
Bài tập thực hành ................................................................................. 33
Chương 3 VÒNG LẶP VÀ CẤU TRÚC DỮ LIỆU MẢNG ................ 35
3.1 Vòng lặp while ............................................................................. 35
3.2 Cấu trúc dữ liệu mảng .................................................................. 41
3.3 Vòng lặp for ................................................................................. 46
3.4 Break, continue và pass................................................................ 49
Bài tập có lời giải ................................................................................. 50
Bài tập thực hành ................................................................................. 51
Chương 4 NUMPY ................................................................................ 54
4.1 Giới thiệu về Numpy.................................................................... 54
4.2 Cài đặt thư viện numpy ................................................................ 54
4.3 Numpy arrays ............................................................................... 55
5
Bài tập thực hành ................................................................................. 58
Chương 5 SETS VÀ DICTIONARIES ................................................. 60
5.1 Sets............................................................................................... 60
5.2 Dictionaries .................................................................................. 62
Bài tập có lời giải ................................................................................. 67
Bài tập thực hành ................................................................................. 68
Chương 6 STRINGS .............................................................................. 69
6.1 Khái niệm và khởi tạo strings ...................................................... 69
6.2 Hàm xử lý strings ......................................................................... 71
Bài tập thực hành ................................................................................. 73
Chương 7 HÀM ..................................................................................... 74
7.1 Khái niệm và cú pháp .................................................................. 74
7.2 Một số ví dụ .....................................................................................74
7.3 Biến đoạn code bất kỳ thành hàm ................................................ 81
Bài tập có lời giải ................................................................................. 83
Bài tập thực hành ................................................................................. 84
Chương 8 LỖI VÀ SỬA LỖI ................................................................ 86
8.1 Các dạng lỗi trong lập trình ......................................................... 86
8.2 Xử lý lỗi runtime .......................................................................... 87
8.3 Xử lý lỗi logic .............................................................................. 90
8.4 Các lưu ý khi viết code để hạn chế lỗi ......................................... 95
Bài tập thực hành ................................................................................. 97
Chương 9 VẼ VỚI MATPLOTLIB ....................................................... 99
9.1 Cách thức vẽ trên màn hình kỹ thuật số ....................................... 99
9.2 Vẽ với thư viện matplotlib ......................................................... 100
9.3 Vẽ đồ thị trong tọa độ cực.......................................................... 106
9.4 Tùy chỉnh hình vẽ ...................................................................... 108
9.5 Vẽ trên nhiều phân vùng với subplotlib ..................................... 116
Bài tập thực hành ............................................................................... 120
6
PHỤ LỤC .............................................................................................. 122
Mã nguồn bài tập có lời giải chương 2 .............................................. 122
Mã nguồn bài tập có lời giải chương 3 .............................................. 127
Mã nguồn bài tập có lời giải chương 5 .............................................. 131
Mã nguồn bài tập có lời giải chương 7 .............................................. 135
Keywords của Python ........................................................................ 142
Cài đặt các thuật toán sắp xếp bằng Python ...................................... 145
Cài đặt các thuật toán tìm kiếm trên mảng bằng Python ................... 151
Cài đặt các thuật toán tìm kiếm trên chuỗi bằng Python ................... 158
INDEX ................................................................................................... 161
TÀI LIỆU THAM KHẢO ..................................................................... 163
7
DANH MỤC HÌNH ẢNH
Hình 1-1 Logo của Python. Nguồn: Python Software Foundation ............ 9
Hình 1-2 Cài đặt Python bằng cách tick vào ô Add Python... to PATH ở
cửa sổ cài đặt đầu tiên. ............................................................................. 12
Hình 1-3 Giao diện của Visual Studio Code. .......................................... 12
Hình 1-4 Giao diện trang OnlineGDB. .................................................... 16
Hình 1-5 Ứng dụng Pydroid 3 trên Google Play. .................................... 16
Hình 2-1 Lưu đồ của khối lệnh if. ........................................................... 28
Hình 3-1 Lưu đồ hoạt động của vòng lặp while. ..................................... 35
Hình 3-2 Lưu đồ hoạt động của vòng lặp for. ......................................... 47
8
Chương 1
GIỚI THIỆU VÀ CÀI ĐẶT PYTHON
1.1 Đôi nét về ngôn ngữ lập trình Python
Python là một ngôn ngữ lập trình cấp cao và đa dụng (generalpurpose) được phát triển bởi Guido van Rossum. Phiên bản đầu tiên của
nó được phát hành vào năm 1991. Tên của nó được đặt theo chương trình
hài Monty Python1 của Anh như một cách phản ánh triết lý thiết kế của
Python: một ngôn ngữ lập trình thú vị khi sử dụng.
Hình 1-1 Logo của Python.
Nguồn: Python Software Foundation
Triết lý của ngôn ngữ lập trình Python được mô tả bằng những cách
ngôn trong tài liệu The Zen of Python (PEP 20) như:
▪
▪
▪
▪
Simple is better than complex (tạm dịch: Đơn giản tốt hơn phức
tạp).
Complex is better than complicated (tạm dịch: Phức hợp tốt hơn
phức tạp).
Explicit is better than implicit (tạm dịch: Tường minh tốt hơn là
ngầm định).
Readability counts (tạm dịch: Lưu tâm đến sự dễ đọc hiểu).
Với những triết lý đó, Python hướng tới sự đơn giản, ngắn gọn
trong mã lệnh của mình. Bạn sẽ cảm nhận được điều này khi bắt đầu lập
trình với Python và so sánh nó với các ngôn ngữ như C/C++, Java.
Đến nay, Python đã được phát triển qua nhiều phiên bản. Hai nhóm
phiên bản được sử dụng hiện nay là Python 2.x và Python 3.x. Tuy nhiên,
1
Theo General Python FAQ, docs.python.org
9
các phiên bản 2.x đã không còn được hỗ trợ đầy đủ từ ngày 1/1/20201.
Phiên bản mới nhất của Python là 3.10 (phát hành ngày 4/10/2021)2.
1.2 Lịch sử phát triển Python3
Python được bắt đầu phát triển vào cuối những năm 1980 bởi
Guido van Rossum tại Centrum Wiskunde & Informatica (CWI), Hà Lan
như một ngôn ngữ kế thừa của ngôn ngữ lập trình ABC có khả năng xử lý
ngoại lệ và giao tiếp với hệ điều hành Amoeba.
Python được bắt đầu phát triển vào tháng 12 năm 1989. Vào thời
điểm đó, van Rossum là tác giả duy nhất của dự án, với tư cách là nhà phát
triển chính, cho đến ngày 12 tháng 7 năm 2018. Vào tháng 1 năm 2019,
các nhà phát triển cốt lõi Python đã bầu ra một Hội đồng chỉ đạo gồm năm
thành viên để lãnh đạo dự án.
Python 2.0 được phát hành vào ngày 16 tháng 10 năm 2000, với
nhiều tính năng mới. Python 3.0, được phát hành vào ngày 3 tháng 12 năm
2008, với nhiều tính năng chính vẫn hỗ trợ ngược Python 2.6.x và 2.7.x.
Các bản phát hành của Python 3 tích hợp tiện ích 2to3 giúp dịch mã tự
động từ Python 2 sang Python 3.
Python 2.7 ban đầu được chỉ định sẽ chấm dứt hoạt động vào
năm 2015, nhưng sau đó bị hoãn lại đến năm 2020 vì những lo ngại về
việc chuyển đổi các code Python 2 hiện có sang Python 3. Từ thời điểm
đó, Python 2 không nhận được thêm bất kỳ bản vá bảo mật hoặc cải tiến
nào nữa.
Sau khi Python 2 bị ngừng hỗ trợ, chỉ còn Python 3.6.x và các phiên
bản mới hơn được hỗ trợ. Một thời gian sau, Python 3.6 cũng bị ngừng hỗ
trợ. Đến năm 2021, Python 3.9.2 và 3.8.8 được phát triển vì tất cả các phiên
bản Python trước (bao gồm 2.7) đều có vấn đề bảo mật có thể khiến máy
tính bị thực thi mã từ xa và nhiễm độc bộ nhớ web cache.
Vào năm 2022, Python 3.10.4 và 3.9.12 được phát triển và các bản
cũ hơn bao gồm 3.8.13 và 3.7.13 được cập nhật vì nhiều vấn đề bảo mật.
1
Theo PEP 373 -- Python 2.7 Release Schedule
Theo PEP 619 -- Python 3.10 Release Schedule
3
Theo https://en.wikipedia.org/wiki/Python_(programming_language)
2
10
1.3 Cài đặt Python
Có nhiều cách khác nhau để lập trình với Python. Phần này mô
tả ba cách phù hợp với các nhóm người dùng với điều kiện về thiết bị
khác nhau.
Cách 1. Lập trình Python trên máy tính sử dụng VS Code
Nếu bạn sở hữu một máy tính cá nhân thì nên dùng cách này để
tận dụng được đầy đủ chức năng của Python một cách thuận tiện.
Trước tiên, bạn cần cài đặt trình biên dịch Python (Python
interpreter). Nên chọn phiên bản Python 3.7 hoặc mới hơn.1 Một lưu ý
khi cài đặt Python intepreter là bạn nên tick vào ô “Add Python ... to
PATH” ở cửa sổ cài đặt đầu tiên (xem Hình 1-2).
Sau khi đã cài đặt xong trình biên dịch Python, bạn nên cài đặt một
editor (trình soạn thảo) hoặc một IDE (Integrated Development
Environment) để lập trình Python được dễ dàng hơn. Có nhiều editor,
IDE khác nhau hỗ trợ lập trình Python. Trong giáo trình này, chúng tôi
khuyến nghị sử dụng Visual Studio Code2 (VS Code). Editor này có các
ưu điểm như:
▪
▪
▪
▪
Miễn phí, mã nguồn mở, hỗ trợ nhiều nền tảng (Windows, Linux,
Mac).
IntelliSense: giúp viết code nhanh chóng hơn bằng cách đưa ra các
lựa chọn tự động hoàn thành code cho bạn.
Hỗ trợ tìm và sửa lỗi (debug) hiệu quả.
Nhiều extension hữu ích: như kết nối với Git, đọc file Jupyter
Notebook (.ipynb), hỗ trợ Docker.
1
Download Python phiên bản mới nhất tại https://www.python.org/downloads/. Với
những phiên bản cũ, download tại https://www.python.org/ftp/python/.
2
Download bản cài đặt VS Code tại https://code.visualstudio.com/download.
11
Hình 1-2 Lưu ý: Khi cài đặt Python nên tick vào ô Add Python ... to PATH để
thuận tiện chạy các Scripts Python về sau..
Hình 1-3 Giao diện của Visual Studio Code.
Sau khi cài đặt VS Code xong, bạn nên thực hiện các bước sau để tạo một
file code Python đầu tiên và cũng để VS Code hoàn tất cài đặt các extension
hỗ trợ lập trình Python.
12
1. Chọn File > Open Folder…
2. Tạo mới hoặc chọn một thư mục rồi nhấn Select Folder.
Lưu ý: đối với máy tính sử dụng Windows, bạn nên chọn một thư
mục trong ổ D: hoặc một ổ đĩa mà bạn có đầy đủ quyền chạy các
mã lệnh. Không dùng các thư mục có tên “python” hoặc “code”
vì có thể gây lỗi về sau. Tên và đường dẫn thư mục tốt nhất là
không chứa khoảng trắng và không chứa dấu tiếng Việt.
13
3. Nhấn vào biểu tượng
và nhập tên file.
Lưu ý: Tên file phải có phần mở rộng .py. Không nên dùng tên file
python.py hoặc code.py để tránh bị lỗi khi chạy. Tên file tốt nhất là
không chứa khoảng trắng và không chứa dấu tiếng Việt.
4. Sau khi tạo file xong, VS Code có thể hỏi bạn có muốn cài đặt
extension cho Python không. Hãy chọn Install.
5. Nhập nội dung sau đây vào file vừa tạo:
#%%
print("Xin chao!")
6. Nhấn Shift-Enter để chạy.
Lưu ý: Lúc này VS Code có thể hỏi bạn muốn cài đặt các
extension hỗ trợ không, hãy chọn Install.
7. Nếu kết quả hiện ra như hình sau tức là bạn đã hoàn thành cài đặt
và chạy thành công đoạn lệnh Python đầu tiên.
8. Chọn File > Auto Save để VS Code tự động lưu code.
Lưu ý: Nếu không dùng Auto Save thì phải lưu (Save) file code
thủ công bằng cách nhấn Ctrl-S mỗi khi muốn lưu.
14
Cách 2. Lập trình Python trên máy tính sử dụng trình duyệt web
Nếu bạn sử dụng máy tính công cộng hoặc một máy tính không thể
cài đặt Python thì bạn có thể sử dụng trình duyệt web có kết nối internet
và truy cập vào địa chỉ sau để lập trình Python:
https://www.onlinegdb.com/online_python_compiler.
Lưu ý: Cách này không đảm bảo hỗ trợ đầy đủ chức năng của
Python. Chỉ nên dùng khi không thể cài đặt Python và VS Code như
cách 1.
15
Hình 1-4. Giao diện trang OnlineGDB.
Cách 3. Lập trình Python sử dụng smartphone
Trong trường hợp không có máy tính, bạn vẫn có thể lập trình
Python bằng cách sử dụng smartphone và cài đặt ứng dụng Pydroid 3
(hoặc một ứng dụng tương tự).
Lưu ý: cách này không được khuyến khích sử dụng vì không hỗ trợ
đủ tính năng của Python. Chỉ nên sử dụng tạm thời cách này trong một thời
gian ngắn khi không thể dùng máy tính.
Hình 1-5 Ứng dụng Pydroid 3 trên Google Play.
1.4 Một số lời khuyên hữu ích cho những người mới
Lập trình là một kỹ năng. Vì vậy nếu muốn lập trình tốt không có
cách nào khác ngoài thực hành. Tự mình thực hành càng nhiều càng tốt!
Một số kinh nghiệm khi luyện lập trình:
16
▪
Cảm thấy không hiểu rõ khi lần đầu học về một khái niệm, kỹ năng
lập trình. Điều này là hoàn toàn bình thường! Bạn chỉ cần bỏ thêm
chút thời gian xem lại một vài lần, rồi tự mình ngồi code lại nội
dung được học thì sẽ dần dần hiểu rõ.
Thậm chí đôi khi bạn đã rất cố gắng mà vẫn cảm thấy không hiểu rõ
hết. Không sao cả! Có một hiện tượng là: dường như não của chúng
ta tự động tổng hợp kiến thức mà nó từng biết qua. Sau một học kỳ,
hoặc vài tháng, thậm chí một năm sau, bạn sẽ ngạc nhiên khi gặp lại
kiến thức lúc trước bạn thấy bế tắc: lúc này bạn hiểu nó rất rõ ràng!
Vì vậy, đừng ngại khi học qua một lần mà chưa hiểu rõ.
▪
▪
▪
Keep learning!
Những lần đầu lập trình đôi khi giống học thuộc lòng, sao chép code.
Tức là bạn xem code mẫu rồi gõ lại giống như vậy. Điều này cũng
hoàn toàn bình thường! Học thuộc luôn luôn là một phần của việc thu
nạp kiến thức.
Đừng ngại ngồi gõ lại code mẫu. Tự mình gõ lại code khác xa với
việc ngồi nhìn code và nghĩ rằng mình hiểu. Gõ lại code giúp bạn trải
nghiệm lập trình. Khi bạn gõ và chạy code, bạn sẽ tự nhiên ghi nhớ,
tư duy và phát hiện các lỗi, các vấn đề trong đoạn lệnh. Bạn sẽ hiểu
nó cặn kẽ và từ từ sẽ tự viết được các đoạn code theo ý mình.
Internet có thể rất hữu ích. Nếu gặp những lỗi khó hiểu khi lập
trình, hoặc nghĩ mãi chưa ra cách lập trình cho một vấn đề, bạn có
thể thử google. Nhiều khả năng bạn sẽ tìm được lời giải từ các diễn
đàn, các bài viết về lập trình.
Tuy nhiên, đừng lạm dụng! Lúc nào cũng tra google trước khi tự
mình tìm cách giải quyết, hoặc chỉ copy code mà không hiểu, chắc
chắn sẽ có hại cho bạn!
Ngoài ra, bạn cũng nên cẩn thận với vấn đề đạo văn (plagiarism).
Nên tìm hiểu về quy định bản quyền của đoạn code mà bạn định sử
dụng và nhớ phải ghi nguồn.
▪
Thực hành càng nhiều càng tốt!
17
Chương 2
PHÉP TOÁN CƠ BẢN, BIẾN
VÀ NHẬP XUẤT TRONG PYTHON
Chương này giúp bạn làm quen với các phép toán cơ bản, khái niệm
biến (variables) trong lập trình và các hàm cơ bản để nhập xuất dữ liệu
trong Python.
2.1 Sử dụng VS Code như một máy tính cầm tay
Phần này demo một số cách thực thi lệnh Python với VS Code. Bạn
có thể tận dụng những cách này để biến VS Code với Python thành một
công cụ tính toán như máy tính cầm tay (calculator).
Lưu ý: Trước khi có thể chạy code Python trong VS Code, bạn cần
Cài đặt Python (xem mục 1.3 Cài đặt Python).
Sau đây giới thiệu ba cách thực thi lệnh Python trong VS Code.
Cách 1. Tạo và thực thi cell
Để tạo một cell, bạn dùng cú pháp #%% Tên gợi nhớ cho cell
như ví dụ sau:
Để chạy cell, bạn đặt con nháy vào 1 dòng bất kỳ trong cell (nằm giữa 2
đường kẻ màu xanh như trong hình trên), và nhấn Run Cell (nằm ở ngay
phía trên dòng #%%) hoặc sử dụng tổ hợp phím tắt Shift-Enter.
Khi bạn chạy cell lần đầu tiên, VS Code sẽ load Python interpreter rồi mới
thực thi code nên mất thời gian một chút. Từ lần chạy thứ 2, code sẽ được
thực thi ngay vì Python interpreter đã được load vào bộ nhớ rồi.
Cách 2. Thực thi code trong cửa sổ interactive
Để sử dụng cách này trước tiên bạn phải chạy ít nhất một cell theo
cách 1 để VS Code load Python interpreter và khởi tạo cửa sổ interactive
(như hình dưới).
18
Trong cửa sổ interactive, bạn có thể nhập code vào dòng lệnh (nằm
dưới cùng cửa sổ interactive, tại vị trí có ghi dòng chữ Type ‘python’ code
here and press Shift+Enter to run (như hình dưới). Khi nhập xong, nhấn
Shift+Enter để thực thi.
2.2 Các phép toán
Python hỗ trợ các phép toán cơ bản như mô tả trong bảng sau.
Phép toán
Cú pháp
Code mẫu
Kết quả
Trị tuyệt đối
abs()
abs(-2)
2
Cộng
+
2+5
7
Trừ
-
3-1
2
Nhân
*
3*2
6
19
Chia
/
5/2
2.5
Chia lấy dư
%
7%2
1
Lũy thừa
**
3**2
9
Lũy thừa 10
e
4e3
4*103 = 4000
Số phức
j
2 + 5j
2 + 5i
Nếu bạn muốn tính những hàm toán học khác như khai căn, lượng giác, thì
cần sử dụng package math. Cú pháp như sau:
import math
math.cos(3.14)
Một số hàm toán học được liệt kê trong bảng bên dưới1:
Phép toán
Cú pháp
Code mẫu
Kết quả
Số π
math.pi
math.pi
3.1415…
Số e
math.e
math.e
2.7182
Vô cùng
math.inf
math.inf
inf
Cosine
math.cos()
math.cos(3.14)
-0.9999
Sine
math.sin()
math.sin(2*3.14)
-0.0031
Arc cosine
math.acos()
math.acos(1)
0
Arc sine
math.asin()
math.asin(-1)
-1.5707
Tangent
math.tan()
math.tan(5)
-3.3805
Trị tuyệt đối
math.fabs()
math.fabs(-5.6)
5.6
Ước chung lớn nhất math.gcd()
math.gcd(20, 90)
10
Hàm mũ
math.exp()
math.exp(5)
148.4131
Hàm log
math.log()
math.log(8)
2.0794
math.log(8, 2)
3
Căn bậc 2
math.sqrt()
math.sqrt(9)
3
Ghi chú: Khi cần tra cứu thông tin của một hàm, bạn có thể dùng cú pháp
với dấu chấm hỏi, ví dụ: lệnh math.log? sẽ hiện thông tin về hàm log.
1
Xem bảng liệt kê đầy đủ tại https://docs.python.org/3/library/math.html
20
2.3 Biến
Biến (variables) là một trong những khái niệm căn bản nhất trong
lập trình. Một biến có thể xem như một nơi chứa dữ liệu đơn giản, phục vụ
cho các tác vụ được lập trình. Ví dụ, khi viết chương trình vẽ đồ thị của
một hàm số bậc 2 có dạng y = ax2 + bx + c, ta có thể tạo ra các biến để lưu
giá trị của các hệ số a, b và c.
Để tạo ra một biến, bạn cần tuân theo các quy định cú pháp (syntax)
tạo biến. Trong Python các quy định về biến như sau:
1. Để tạo biến trong Python, bạn chỉ cần ghi tên biến và gán giá trị
cho nó, ví dụ các dòng sau lệnh (chú ý mỗi dòng lệnh phải nằm
trên một hàng riêng, dùng phím Enter để xuống dòng):
so1 = 4
so2 = 15
đã tạo ra 2 biến có tên so1, so2 với các giá trị là 4, 15 tương ứng.
Ghi chú: [Dành cho bạn nào đã biết ngôn ngữ lập trình như C,
C++] Python không yêu cầu khai báo biến hoặc khai báo kiểu dữ
liệu cho biến. Khi bạn gán giá trị cho biến, Python sẽ tự động xác
định kiểu dữ liệu cho biến đó.
2. Tên biến phải bắt đầu bằng chữ cái hoặc dấu _ (dấu dash tạo ra
bằng cách nhấn tổ hợp phím Shift -)
Ví dụ: các biến so1, _so1 và _1so là hợp lệ, nhưng biến 1so là
không hợp lệ vì bắt đầu bằng chữ số 1.
3. Tên biến không được chứa khoảng trắng hoặc ký tự đặc biệt
(ký tự đặc biệt là các ký tự không phải chữ cái và chữ số (ngoại trừ
dấu dash _), ví dụ @, &, ! là một số ký tự đặc biệt).
21
Ví dụ: các biến phuongtrinh1 và phuong_trinh_1 là hợp lệ,
nhưng
biến
phuong
trinh1,
phuongtrinh-1,
phuongtrinh#1 là không hợp lệ.
4. Tên biến phải khác keywords của Python. Trong Python, cũng như
các ngôn ngữ lập trình khác, một số từ đã được dành riêng cho các
chức năng của ngôn ngữ, ví dụ if, for, while. Vì vậy bạn
không được dùng nhũng từ này đặt tên biến.
Ví dụ: các biến có tên if, for, break, import là không hợp
lệ vì chúng là các keywords, nhưng các biến if1, for_,
break_A một thì hợp lệ vì có chứa thêm các ký tự khác nên không
còn là keywords.
Ghi chú: để nhận biến một từ có phải keyword không, bạn quan sát
màu sắc của nó trong VS Code (VS Code tự chuyển từ thành màu
xanh da trời nếu là keyword). Xem danh sách các keywords trong
phần Phụ lục.
5. Tên biến có phân biệt chữ hoa và chữ thường.
Ví dụ: biến so1 và So1 là 2 biến khác nhau.
Ghi chú: mặc dù bạn có thể tạo ra 2 biến so1 và So1 trong một
chương trình, tuy nhiên, một kinh nghiệm viết code tốt là bạn nên
tránh tạo ra những biến quá giống nhau vì chúng dễ gây nhầm
lẫn và dễ dẫn tới lỗi khi lập trình.
Ngoài các quy định cú pháp bắt buộc ở trên, khi lập trình bạn cũng
nên tuân theo các kinh nghiệm đặt tên biến sau đây sẽ giúp code của bạn
được chuyên nghiệp hơn, khó bị mắc lỗi hơn.
1. Tránh đặt tên biến trùng với tên hàm cài sẵn (built-in
functions). Hàm cài sẵn là các hàm được cung cấp mặc định trong
Python hoặc các packages (xem mục 4.2), ví dụ hàm print,
input. Việc đặt tên biến trùng với tên hàm cài sẵn sẽ làm chương
trình có thể gặp lỗi khi bạn gọi các hàm này sau khi đã tạo biến.
Bạn có thể chạy thử dòng code sau:
print("Xin chao")
Sau đó, chạy đoạn code sau:
print = 5
print("Xin chao")
22
Để ý rằng lần chạy dòng lệnh print thì hàm sẽ hoạt động bình
thường. Nhưng khi chạy đoạn code có dòng print = 5 (tức là ta
tạo ra biến tên print và gán giá trị 5 cho nó) thì hàm sẽ báo lỗi.
Để xử lý lỗi này, bạn chạy lệnh del print để xóa biến print trong
bộ nhớ, khi đó hàm print sẽ hoạt động trở lại.
Ghi chú: Trong VS Code, để kiểm tra xem một từ có trùng tên hàm
cài sẵn không, bạn nhấn tổ hợp phím Ctrl-Space (thanh cách). Nếu
là hàm cài sẵn thì sẽ xuất hiện bảng thông tin như hình dưới:
2. Đặt tên biến có ý nghĩa. Kinh nghiệm đơn giản này đã được chứng
minh trong thực tế có thể giúp cải thiện đáng kể code của bạn: dễ
đọc, dễ bảo trì, sửa lỗi và dễ phát triển hơn. Điều này đặc biệt cần
thiết khi bạn viết những chương trình phức tạp và code được viết
bởi một nhóm nhiều người. Đừng ngại các tên dài, chỉ ngại các tên
khó hiểu!
Ví dụ: Thay vì đặt tên biến là a, N, f, g, bạn hãy đặt: he_so_a,
so_thiet_bi, ham_loc_du_lieu, ham_phan_tich sẽ giúp
chương trình của bạn dễ đọc hơn rất nhiều.
Ghi chú: Để liệt kê các tên bạn đã tạo, dùng lệnh whos. Để xóa một biến,
dùng lệnh del ten_bien, ví dụ del he_so_a.
2.4 Nhập xuất cơ bản
Dữ liệu đưa vào chương trình có thể thông qua việc gán trực tiếp
vào biến (như mục trên), hoặc nhập từ bàn phím, từ các thiết bị chuyên
dụng (cảm biến, camera), hoặc từ file dữ liệu. Bên dưới giới thiệu cách
nhập dữ liệu cơ bản từ bàn phím.
Để nhập dữ liệu từ bàn phím bạn có thể dùng hàm input(), như
các ví dụ sau:
#%% Ví dụ 1: nhập chữ
ho_ten = input('Xin nhap ho ten:')
23
#%% Ví dụ 2: nhập số nguyên
so_thiet_bi = int(input('Nhap so thiet bi:'))
#%% Ví dụ 3: nhập số thực
diem_trung_binh = int(input('Nhap diem trung binh:'))
Trong ví dụ 1, khi chạy dòng lệnh nhập sẽ xuất hiện ô đợi người
dùng nhập tên như sau (trong VS Code ô này xuất hiện ở trên cùng của cửa
sổ VS Code):
Sau khi người dùng nhập tên và nhấn Enter thì tên được nhập sẽ
được lưu vào biến ho_ten.
Trong ví dụ 2, để ý trong dòng lệnh nhập có hàm int(), hàm này
có công dụng kiểm tra và chuyển đổi dữ liệu được nhập thành kiểu số
nguyên. Khi chạy ví dụ này bạn cũng sẽ thấy xuất hiện ô nhập tương tự
như trên, nhưng lưu ý rằng, bạn cần nhập số nguyên, nếu không chương
trình sẽ báo lỗi.
Trong ví dụ 3, đoạn lệnh nhập tương tự ví dụ 2, chỉ khác ở hàm
float() thay cho hàm int(). Hàm float() đổi dữ liệu được nhập về kiểu
số thực.
Lưu ý: Khi không dùng hàm chuyển đổi kiểu dữ liệu (type casting)
như hàm int(), float(), thì dữ liệu trả về từ hàm input() sẽ có kiểu chữ
(string) và không thể thực hiện các phép toán.
Tương tự như việc nhập dữ liệu, việc xuất dữ liệu cũng có nhiều
cách khác nhau như gán trực tiếp vào biến (để sử dụng tiếp tục trong
chương trình), hoặc in chữ, vẽ hình lên màn hình, hoặc truyền tới các thiết
bị xuất (loa, máy in, thiết bị điều khiển), hoặc lưu xuống file. Bên dưới
giới thiệu cách in dữ liệu đơn giản ra màn hình.
Để in text lên màn hình, bạn có thể dụng hàm print() của Python
như các ví dụ bên dưới:
#%% Ví dụ 1: in trực tiếp văn bản
print("Xin chao")
24
#%% Ví dụ 2: in nội dung 1 biến
ho_ten = "Tran An"
print(ho_ten)
#%% Ví dụ 3: in nội dung 1 biến kèm thông báo
print("Ho ten cua ban:", ho_ten)
#%% Ví dụ 4: in nội dung nhiều biến
x1 = 15.3456
x2 = 26.1234
print("Nghiem 1:", x1, " Nghiem 2:", x2)
#%% Ví dụ 5: định dạng biến kiểu số thực
print("Nghiem 1: %.2f Nghiem 2: %.2f" % (x1,x2)) # chỉ
lấy 2 chữ số thập phân
Khi thực thi ví dụ 1, dòng chữ Xin chao! sẽ được in ra màn hình.
Khi thực thi ví dụ 2, dòng chữ Tran An (nội dung của biến
ho_ten) sẽ được in ra màn hình.
Khi thực thi ví dụ 3, dòng chữ Ho ten cua ban: Tran An sẽ
được in ra màn hình.
Khi thực thi ví dụ 4, dòng chữ Nghiem 1: 15.3456 Nghiem
2: 26.1234 sẽ được in ra màn hình.
Khi thực thi ví dụ 5, dòng chữ Nghiem 1: 15.35 Nghiem 2:
26.12 sẽ được in ra màn hình (để ý giá trị của x1, x2 chỉ in ra 2 chữ số
thập phân). Chúng ta xem chi tiết dòng lệnh trong ví dụ này:
print("Nghiem 1: %.2f Nghiem 2: %.2f" % (x1,x2))
Đoạn code %.2f có nghĩa là sẽ in ra số thực với 2 số thập phân.
Để in 3 số thập phân bạn sẽ code thành: %.3f (con số nằm trước chữ f
chính là số lượng chữ số thập phân sẽ in ra).
25
Các biến cần in được đặt trong đoạn code % ( ). Ví dụ: %
(x1,x2) sẽ in ra giá trị của các biến x1, x2. Lưu ý các biến được in ra
theo đúng thứ tự bạn liệt kê trong đoạn code này.
Lưu ý: Trong ví dụ 5, dấu # trong đánh dấu đoạn ghi chú
(comments). Mọi nội dung đặt sau dấu # sẽ được trình dịch Python bỏ
qua, không thực thi. Thông thường trong lập trình, comments được sử dụng
để ghi chú cho những đoạn lệnh quan trọng, hoặc để giải thích cho công
dụng các hàm hoặc các đoạn lệnh phức tạp. Khi viết comments nên viết rõ
ràng nhưng ngắn gọn. Tránh ghi quá nhiều comments cho những đoạn code
đơn giản, vì có thể làm code rườm rà, khó đọc hơn.
2.5 Lệnh if
Lệnh if là cấu trúc rẽ nhánh trong Python. Nói một cách đơn giản,
cấu trúc rẽ nhánh là lựa chọn chạy lệnh này hoặc lệnh khác. Ví dụ khi giải
phương trình bậc 2, nếu giá trị biệt số delta ≥ 0 thì ta sẽ chạy lệnh tính
nghiệm, còn nếu giá trị biệt số delta < 0 thì ta chạy lệnh in ra thông báo
phương trình vô nghiệm. Lệnh if chính là sự diễn đạt “nếu” trong lập trình.
Để sử dụng được lệnh if, trước tiên ta cần biết quy tắc cú pháp của
nó. Trong Python, lệnh if được quy định cú pháp như sau:
if dieu_kien_1:
khoi_lenh_1
elif dieu_kien_2:
khoi_lenh_2:
elif dieu_kien_3:
khoi_lenh_3:
else:
khoi_lenh_N
khoi_lenh_sau_if
Luồng hoạt động của khối lệnh if trên được mô tả trong lưu đồ ở Hình 2-1.
Một cách cụ thể, trong cú pháp if trên,
▪ if, elif, else là các từ khóa (bắt buộc viết chính xác như vậy).
Lưu ý: Chỉ khối if là bắt buộc có, còn khối elif và else có thể
xuất hiện tùy ý. Cụ thể, khối elif có thể không xuất hiện hoặc xuất hiện
26
1 lần hoặc nhiều lần, còn khối else có thể không xuất hiện hoặc xuất hiện
1 lần. Ví dụ, chúng ta có thể viết lệnh if như sau:
if dieu_kien_1:
khoi_lenh_1
khoi_lenh_sau_if
hoặc viết như sau:
if dieu_kien_1:
khoi_lenh_1
else:
khoi_lenh_N
khoi_lenh_sau_if
hoặc viết như sau:
if dieu_kien_1:
khoi_lenh_1
elif dieu_kien_2:
khoi_lenh_2:
khoi_lenh_sau_if
▪
dieu_kien_1,
dieu_kien_2,
dieu_kien_3,
dieu_kien_N là các mệnh đề logic: có giá trị True hoặc False
(đúng hoặc sai) khi chạy code. Ví dụ: 1>2 là một mệnh đề sai (giá
trị False), 5<6 là mệnh đề đúng (True), N<10: mệnh đề này đúng
hoặc sai tùy thuộc vào giá trị của biến N khi chạy code, ví dụ nếu
N = 9 thì mệnh đề đúng (9<10). Bảng sau đây liệt kê các toán tử so
sánh và toán tử kết hợp có thể dùng trong khối điều kiện.
Toán tử
Cú pháp
Code mẫu
Kết quả
So sánh lớn hơn
>
5>2
True
So sánh nhỏ hơn
<
5<2
False
So sánh bằng
==
5==2
False
So sánh khác
!=
5!=2
True
27
So sánh lớn hơn
>=
hoặc bằng
5>=2
True
So sánh nhỏ hơn
<=
hoặc bằng
5<=5
True
Và
and
(5<2) and (2<4)
False
Hoặc
or
(5<2) or (2<4)
True
Phủ định
not
not (5>=2)
False
Hình 2-1 Lưu đồ của khối lệnh if.
Khi được viết đúng cú pháp, lệnh if sẽ hoạt động theo nguyên tắc:
điều kiện nào đúng thì chỉ chạy duy nhất khối lệnh ngay dưới điều
kiện đó (các khối lệnh khác sẽ bị bỏ qua). Các điều kiện sẽ được kiểm tra
28
lần lượt từ trên xuống: dieu_kien_1 được kiểm tra trước, sau đó đến
dieu_kien_2, rồi dieu_kien_3… Ví dụ:
▪
Nếu dieu_kien_1 đúng (giá trị True) thì khối lệnh
khoi_lenh_1 sẽ được chạy. Sau khi chạy xong khoi_lenh_1
thì chương trình sẽ nhảy đến khoi_lenh_sau_if, tức là toàn
bộ các dòng code còn lại trong lệnh if sẽ bị bỏ qua.
▪
Nếu dieu_kien_1 sai (giá trị False) thì khối lệnh
khoi_lenh_1 sẽ bị bỏ qua. Lúc này trình biên dịch Python sẽ
kiểm tra dieu_kien_2. Nếu dieu_kien_2 đúng thì sẽ chạy
khoi_lenh_2. Sau khi chạy xong khoi_lenh_2 thì chạy đến
khoi_lenh_sau_if. Nếu dieu_kien_2 sai thì kiểm tra
dieu_kien_3 và thực hiện tương tự như trên.
▪
Khi tất cả các điều kiện đều sai, nếu có khối else thì lệnh trong
khối else sẽ được chạy (tức lệnh khoi_lenh_N sẽ chạy). Nếu
không có khối else thì sẽ chạy khoi_lenh_sau_if.
Lưu ý:
Một khối lệnh có thể bao gồm nhiều dòng lệnh.
Mỗi dòng lệnh Python được đặt trên 1 dòng. Nghĩa là bạn phải
xuống dòng (enter) khi viết xong 1 câu lệnh.
Các câu lệnh trong một khối lệnh phải có thụt đầu dòng
(indentation) bằng nhau. Tức là nếu dòng lệnh 1 được thụt đầu
dòng bằng 3 khoảng trắng (space) thì dòng lệnh 2 (trong khối đó)
cũng phải như vậy. Nếu bạn thụt đầu dòng 4 khoảng trắng, hoặc 2
khoảng trắng khi viết dòng lệnh 2 thì sẽ bị lỗi. Đây là quy định cú
pháp của Python nhằm đảm bảo chương trình ngăn nắp, dễ đọc.
▪
▪
▪
Ví dụ 2.1: Nhập 1 số nguyên và xác định số được nhập là chẵn hay lẻ.
#%% Xác định chẵn lẻ
N = int(input('Xin nhap 1 so nguyen:'))
if N % 2 == 0:
print(N, 'la so chan.')
else:
print(N, 'la so le.')
29
Trong đoạn lệnh trên, phép toán % là phép chia lấy dư (xem mục 2.2). Nếu
số được nhập chia lấy dư cho 2 bằng 0 (tức là nó chia hết cho 2) thì đây là
số chẵn.
Thực hành: Bạn hãy gõ lại đoạn code trên và thực thi (Shift-Enter) rồi
nhập vào các số nguyên khác nhau để xem kết quả được in ra.
Ví dụ 2.2: Nhập 2 số thực và xác định xem chúng cùng dấu hay trái dấu.
#%% Xác định cùng dấu, trái dấu
so1 = float(input('Xin nhap so thu nhat:'))
so2 = float(input('Xin nhap so thu hai:'))
if so1*so2 < 0:
print('Hai so duoc nhap trai dau.')
elif so1*so2 > 0:
print('Hai so duoc nhap trai dau.')
else:
print('Co mot so bang khong.')
Thực hành: Bạn hãy gõ lại đoạn code trên và thực thi (Shift-Enter) rồi
nhập vào các cặp số thực khác nhau để xem kết quả được in ra. Lý giải
hoạt động của chương trình dựa vào các điều kiện so1*so2 < 0 và
so1*so2 > 0.
Ví dụ 2.3: Nhập 3 số thực và tìm số lớn nhất trong 3 số này.
#%% Tìm số lớn nhất trong 3 số
so1 = float(input('Nhap so thu nhat:'))
so2 = float(input('Nhap so thu hai:'))
so3 = float(input('Nhap so thu ba:'))
so_lon_nhat = so1
if so_lon_nhat < so2:
so_lon_nhat = so2
if so_lon_nhat < so3:
30
so_lon_nhat = so3
print('So lon nhat:', so_lon_nhat)
Thực hành: Bạn hãy gõ lại đoạn code trên và thực thi (Shift-Enter) rồi
nhập vào các bộ số thực khác nhau để xem kết quả được in ra. Lý giải hoạt
động của chương trình (để ý rằng đoạn code trên sử dụng 2 khối if liên tiếp
nhau).
Thực hành: Nhập đoạn mã sau và đặt tên file là if_else_demo.py. Sau đó
hãy thực thi đoạn mã và cho biết kết quả in ra màn hình.
# if-else
a = 10
b = 30
print('demo if-elif-else')
if (a > 10) or (b > 10):
# do something
print('(a > 10) or (b > 10)')
elif (a != 5) and (b <= 7):
# do something
print('(a != 5) and (b <= 7)')
else:
# do something
print('else')
# nested if
if (a == 0) or (b > 20):
if b < 50:
print('nested-if')
else:
print('else-nested-if')
else:
print('if-else')
31
Bài tập có lời giải1
1. Viết chương trình đọc một ký tự từ bàn phím. Nếu ký tự được nhập
là nguyên âm gồm các điểm chữ thành điểm số như cách tính điểm
ở một số trường đại học trên thế giới. Bảng ánh xạ có thể được thể
hiện như sau
Chương trình sẽ đọc ký tự từ người sử dụng. Sau đó, chương trình
sẽ tính toán và hiển thị con số điểm tương ứng. Ngoài ra, chương
trình có thể đưa ra thông báo “yêu cầu nhập lại” trong trường hợp
người dùng nhập vào một ký tự không tồn tại trong bảng trên.
2. Viết chương trình đánh giá hiệu quả làm việc của nhân viên. Một
công ty muốn đánh giá hiệu quả làm việc của nhân viên công ty
theo mỗi năm. Thang đo hiệu quả làm việc sẽ được đánh giá từ 0.0
và giá trị càng cao thì thể hiện năng lực làm việc càng tốt của nhân
viên. Giá trị đánh giá n có thể là 0.0, 0.4 hoặc 0.6 hoặc lớn hơn.
Trong đó, các giá trị giữa 0.0 và 0.4 hoặc 0.4 và 0.6 thì không được
sử dụng. Chi tiết được thể hiện trong bảng sau. Giá trị thưởng cho
Các bài tập có lời giải trong giáo trình này đa số được trích từ sách Stephenson, B.
(2019). The Python Workbook 2nd. Springer. Lời giải được trình bày trong phần Phụ lục.
1
32
mỗi nhân viên sau khi đánh giá sẽ tương ứng với công thức
$2400*n. Hãy viết chương trình đọc vào giá trị n từ người dùng và
hãy chỉ ra rằng hiệu quả làm việc tương ứng của nhân viên có giá
trị n cho hiệu quả công việc là unacceptable, acceptable và
meritorious. Nếu giá trị n không thể hiện đúng như trong bảng thì
đưa ra thông báo “vui lòng nhập lại”.
3. Viết chương trình kiểm tra năm nhuận. Thông thường mỗi năm có
khoảng 365 ngày. Tuy nhiên, thời gian này phụ thuộc vào thời gian
Trái đất hoàn thành một vòng xoay quanh Mặt trời. Điều này dẫn
đến có thể có thêm 1 ngày là ngày 29 tháng 2. Những năm có thêm
ngày này được xem là năm nhuận. Cách tính năm nhuận sẽ được
quyết định bởi một số điều sau:
• Số năm chia hết cho 400 là năm nhuận
• Các năm còn lại:
▪ nếu chia hết cho 100 thì không là năm nhuận
▪ nếu chia hết cho 4 thì là năm nhuận
• Các trường hợp còn lại thì không là năm nhuận
Hãy viết một chương trình đọc vào số năm từ người dùng và hiển
thị thông báo chỉ ra rằng năm vừa nhập có phải là năm nhuận
không.
Bài tập thực hành
1. Viết code tính diện tích tam giác có cạnh đáy dài 10 cm và cao 6
cm.
2. Viết code cho người dùng nhập vào đường kính của 1 hình tròn tùy
ý và tính diện tích hình tròn đó.
3. Viết code kiểm tra biểu thức sau đúng không (True or False).
𝜋 4𝜋
Kiểm tra với x = 𝜋, 2 ,
3
.
sin2 (𝑥) + cos2 (𝑥) = 1
33
4. Viết code cho nhập 3 số thực a, b, c (sử dụng hàm input()), và giải
phương trình bậc hai ax2 + bx + c = 0. In nghiệm tìm được bằng
hàm print().
5. Viết chương trình cho người dùng nhập 3 số thực rồi tìm in ra các
số có trị tuyệt đối nhỏ hơn 10.
6. Viết chương trình cho người dùng nhập 5 số thực rồi tìm max/min
của chúng.
7. Viết chương trình xác định thứ trong tuần của ngày 1 tháng 1.
Thứ trong tuần của ngày 1 tháng 1 đối với một năm được tính theo
công thức sau:
Kết quả của công thức trên là một số nguyên thể hiện thứ trong
tuần. Việc mã hóa thứ sẽ bắt đầu với ngày Chủ nhật với số mã
hóa là 0. Tương tự, ngày thứ Bảy sẽ có giá trị mã hóa là 6. Hãy
sử dụng công thức trên và viết một chương trình đọc số năm từ
người sử dụng. Chương trình sẽ tính toán và in ra thứ tương ứng
với đối ngày 1 tháng 1 của năm mà người dùng nhập.
34
Chương 3
VÒNG LẶP VÀ
CẤU TRÚC DỮ LIỆU MẢNG
Trong chương trước bạn đã được giới thiệu về lệnh if giúp điều
khiển chương trình chạy rẽ nhánh vào các đoạn lệnh khác nhau theo điều
kiện. Trong chương này, bạn sẽ được tìm hiểu về vòng lặp – cấu trúc tự
động thực thi nhiều lần các đoạn lệnh theo kịch bản bạn muốn. Có hai dạng
vòng lặp được hỗ trợ trong Python là vòng lặp while và vòng lặp for.
3.1 Vòng lặp while
Cú pháp của vòng lặp while như sau:
while dieu_kien:
khoi_lenh_lap
khoi_lenh_sau_while
Luồng hoạt động của vòng lặp while được mô tả trong lưu đồ ở
Hình 3-1.
Hình 3-1 Lưu đồ hoạt động của vòng lặp while.
35
Nhìn qua khối lệnh while có cú pháp giống với khối if tối giản.
Hoạt động của khối while như sau: khi dieu_kien còn đúng (True) thì
còn thực thi khoi_lenh_lap (tức là khoi_lenh_lap sẽ được chạy
nhiều lần), khi dieu_kien sai (False) thì sẽ chạy
khoi_lenh_sau_while. Để dễ hiểu hơn, chúng ta xem ví dụ sau.
Ví dụ 3.1: Viết code yêu cầu nhập số N dương. Nếu nhập sai thì cho nhập
lại đến khi đúng.
#%% Nhập số dương
N = -1
while N<=0:
N = int(input('Xin nhap so nguyen duong:'))
print('So duoc nhap N =', N)
Lưu ý: Để vòng lặp while hoạt động được cần thỏa mãn hai điểm sau:
1. Điều kiện dieu_kien phải được khởi tạo trước. Tức là mọi
biến trong dieu_kien phải được gán giá trị sẵn. Thông
thường ta sẽ khởi tạo biến sao cho dieu_kien có giá trị True
ở lần chạy đầu tiên.
2. Khối lệnh khoi_lenh_lap phải có ít nhất 1 dòng lệnh làm thay
đổi điều kiện dieu_kien. Nếu không vòng lặp sẽ chạy không bao
giờ dừng (do dieu_kien không bị thay đổi, nó sẽ đúng (True) mãi
mãi nên vòng lặp sẽ lặp mãi mãi).
Trong ví dụ ở trên, lệnh N = -1 đã khởi tạo giá trị cho biến N. Nếu không
có lệnh này thì điều kiện N<=0 chưa được khởi tạo, sẽ báo lỗi khi chạy.
Ngoài ra, để ý rằng lệnh N = int(input(…)) là câu lệnh có thể làm
thay đổi điều kiện bởi vì nó gán giá trị cho biến N. Khi giá trị của N thay
đổi thì điều kiện N<=0 có thể thay đổi (từ True thành False).
Thực hành: Bạn hãy gõ lại đoạn code trên và thực thi (Shift-Enter) rồi
nhập vào các số nguyên âm, sau đó nhập 1 số nguyên dương và xem kết
quả được in ra.
36
Ví dụ 3.2: Viết code yêu cầu nhập số N dương và tính N!
#%% Tính giai thừa
N = -1
while N<=0:
N = int(input('Xin nhap so nguyen duong:'))
print('So duoc nhap N =', N)
giai_thua = 1
i = 1
while i<=N:
giai_thua *= i # = giai_thua*i
i += 1
print('N! =', giai_thua)
Nhắc lại lưu ý viết lệnh trong Python:
▪
▪
Mỗi dòng lệnh Python được đặt trên 1 dòng. Nghĩa là bạn phải
xuống dòng (enter) khi viết xong 1 câu lệnh.
Các câu lệnh trong một khối lệnh phải có thụt đầu dòng
(indentation) bằng nhau. Tức là nếu dòng lệnh 1 được thụt
đầu dòng bằng 3 khoảng trắng (space) thì dòng lệnh 2 (trong
khối đó) cũng phải như vậy. Nếu bạn thụt đầu dòng 4 khoảng
trắng, hoặc 2 khoảng trắng khi viết dòng lệnh 2 thì sẽ bị lỗi.
Đây là quy định cú pháp của Python nhằm đảm bảo chương
trình ngăn nắp, dễ đọc.
Trong ví dụ trên, các lệnh N = int(input(…)) và i = 1 giúp khởi tạo
điều kiện i<=N. Lệnh i += 1 giúp thay đổi điều kiện. Dòng lệnh
giai_thua *= i tương đương với lệnh giai_thua = giai_thua*i.
Đây là một cách viết tắt phép tính và gán trong Python, ví dụ:
a += 2, tương đương a = a + 2
b /= 3, tương đương b = b / 3
Thực hành: Bạn hãy gõ lại đoạn code trên và thực thi (Shift-Enter) rồi
nhập vào các số nguyên dương N khác nhau và xem kết quả được in ra.
37
Ví dụ 3.3: Viết code yêu cầu nhập số N dương và tính tổng 1+2+…+N.
#%% Tính tổng 1+2+…+N
N = -1
while N<=0:
N = int(input('Xin nhap so nguyen duong:'))
print('So duoc nhap N =', N)
tong = 0
i = 1
while i<=N:
tong += i
i += 1
print('1+2+...+N =', tong)
Trong code trên, để ý lệnh tong = 0. Ở đây chúng ta khởi tạo giá trị cho
tổng là 0 (so với ví dụ 2 ở trên, ta khởi tạo giai thừa bằng 1 vì phép tính
nhân dồn).
Thực hành: Bạn hãy gõ lại đoạn code trên và thực thi (Shift-Enter) rồi
nhập vào các số nguyên dương N khác nhau và xem kết quả được in ra.
Ví dụ 3.4: Viết code tìm max trong 3 số thực nhập bởi người dùng. Sau khi
chạy xong thì hỏi người dùng có muốn chạy lại không. Nếu người dùng
nhấn phím ‘y’ thì chạy lại, nhấn phím khác thì dừng.
#%% Tìm max và lặp lại
chay_tiep = 'y'
while chay_tiep == 'y' or chay_tiep == 'Y':
so1 = float(input('Nhap so thu nhat'))
so2 = float(input('Nhap so thu hai'))
so3 = float(input('Nhap so thu ba'))
so_lon_nhat = so1
if so_lon_nhat<so2:
so_lon_nhat=so2
if so_lon_nhat<so3:
38
so_lon_nhat=so3
print('So lon nhat: ', so_lon_nhat)
chay_tiep = input('Nhan "y" de chay lai, nhan phim
khac de thoat:')
print('Da hoan thanh.')
Trong đoạn code trên, bạn hãy để ý cách biến chay_tiep được khởi tạo
cũng như gán lại giá trị chay_tiep = input(…) để đảm bảo điều kiện
sẽ có lúc sai (False) và vòng lặp có thể dừng.
Thực hành: Bạn hãy gõ lại đoạn code trên và thực thi (Shift-Enter) rồi
nhập vào các số thực, sau đó nhập “y” hoặc “Y” để chạy lại. Nếu nhập
phím khác “y” và “Y” thì chương trình sẽ dừng.
Ví dụ 3.5: Viết code tính ln(1+x) bằng khai triển Taylor1 với |x|<1. Cho
công thức khai triển Taylor của ln(1+x) (với |x|<1) như sau:
#%% Tính ln(1+x) bằng khai triển Taylor
x = float(input('Nhap x (-1<x<1):'))
i = 1
tu_so = x
mau_so = i
so_hang = tu_so/mau_so
tong = so_hang
while abs(so_hang)>1e-10:
i += 1
tu_so *= -x
mau_so = i
so_hang = tu_so/mau_so
tong += so_hang
print('ln( 1 +',x,') =',tong)
1
https://en.wikipedia.org/wiki/Taylor_series
39
Trong code trên, đoạn lệnh x = float(input(…) giả định rằng người
dùng sẽ nhập x đúng yêu cầu (|x|<1).
Để viết code trên, ta cần phân tích biểu thức của khai triển Taylor:
Để ý rằng biểu thức tổng này có các số hạng có tính chất lặp: tử số của số
hạng sau bằng tử số của số hạng trước đó nhân với -x. Còn mẫu số của các
số hạng thì tăng dần từ 1, 2, 3…
Các lệnh:
i = 1
tu_so = x
mau_so = i
so_hang = tu_so/mau_so
tong = so_hang
là các lệnh khởi tạo cho số hạng và tổng. Khi khởi tạo xong, ta có thể tính
số hạng sau bằng theo phân tích lặp ở trên.
Ngoài ra, bởi vì khai triển Taylor của ln(1+x) là một dãy hội tụ (khi
|x|<1), hay nói cách khác, các số hạng trong dãy càng về sau càng có giá
trị tuyệt đối nhỏ (tiến về 0). Vì vậy ta có thể thiết lập điều kiện dừng của
vòng lặp khi giá trị của số hạng đã trở nên rất nhỏ, ví dụ 10-10 như trong
điều kiện trên code: abs(so_hang)>1e-10.
Thực hành: Viết thêm đoạn code bắt buộc người dùng nhập x đúng yêu
cầu (|x|<1).
Bạn cũng có thể kiểm tra độ chính xác của code được viết bằng
cách tính giá trị của ln(1+x) và đối chiếu. Ví dụ đoạn code sau có thể dùng
để tính giá trị cho ln(1+x):
import math
print('ln( 1 +',x,') =',math.log(1+x))
Thực hành: Nhập đoạn mã sau và đặt tên là while_demo.py, sau đó hãy
thực thi đoạn mã và cho biết kết quả in ra màn hình.
40
print('demo - iteration while')
i = 0
while i < 10:
print(i)
i += 1
3.2 Cấu trúc dữ liệu mảng
Trước khi giới thiệu vòng lặp for, chúng ta xem về một dạng cấu
trúc dữ liệu cơ bản rất phổ biến trong Python cũng như các ngôn ngữ lập
trình khác: mảng.
Nói một cách đơn giản, một biến có kiểu mảng thì có thể lưu trữ
đồng thời nhiều giá trị. Biến mà bạn được giới thiệu trong chương trước
chỉ có thể lưu 1 giá trị. Khi bạn gán giá trị mới thì giá trị cũ sẽ mất. Mảng
thì không như vậy, nó có thể chứa một lúc nhiều giá trị.
Ví dụ, bạn sẽ cần dùng mảng nếu muốn lưu danh sách tên của các
sinh viên trong 1 lớp. Nếu không dùng mảng, bạn sẽ phải tạo nhiều biến
bình thường để lưu các tên sinh viên, vì mỗi biến chỉ chứa được 1 tên. Cách
làm này vừa bất tiện vừa khó phát triển chương trình, vì khi cần thêm một
sinh viên, bạn phải thêm 1 biến nữa trong code.
Một ví dụ khác là khi bạn cần lưu giá trị nhiệt độ trả về từ một cảm
biến nhiệt mà bạn dùng để theo dõi một thiết bị nào đó (ví dụ bình đun
nước, bình giữ nhiệt). Giả sử mỗi phút cảm biến này sẽ trả về 1 nhiệt độ.
Như vậy, nếu không dùng mảng thì cứ mỗi phút nhiệt độ cũ sẽ bị mất (bị
thay thế bởi nhiệt độ mới). Để lưu lại tất cả các giá trị nhiệt độ sử dụng cho
phân tích về sau (ví dụ để vẽ biểu đồ thay đổi nhiệt độ của thiết bị) thì ta
cần lưu lại tất cả nhiệt độ này. Mảng sẽ giúp bạn lưu lại tất cả nhiệt độ này.
Trong Python, có nhiều cách khác nhau để tạo ra các biến có kiểu
mảng. Trong phần này chúng ta sẽ sử dụng list. Để tạo một list, bạn dùng
dấu ngoặc vuông để đánh dấu bắt đầu và kết thúc list như các ví dụ sau:
#%% Tạo list
list1 = [-2, 3, 5.27, -19, 10]
list2 = ['Tam', 'Thien', 'Hoa', 'Binh']
list3 = ['Tam', 10, 'Thien', 7.3, 'Hoa', 8, 'Binh', 9.2]
41
Có thể thấy mảng tạo bằng cú pháp list chứa được các phần tử có
kiểu dữ liệu khác nhau (số nguyên, số thực, chữ). Các phần tử trong list
được ngăn cách bởi dấu phẩy. Phần tử kiểu chữ phải được đặt trong dấu
nháy đơn ' hoặc nháy kép ''.
Bạn cũng có thể tạo list bằng cách ghép 2 list đã có với nhau:
list4 = list1 + list2
Để xem nội dung của list bạn có thể dùng lệnh print():
print(list4)
Để truy xuất các phần tử trong list, ta cần biết các phần tử của list
đều được đánh số, gọi là index. Có 2 dạng indexing trong list: index không
âm và index âm. Ví dụ, xét
list1 = [-2, 3, 5.27, -19, 10]
Các phần tử trong list này có index như sau:
Phần tử
-2
3
5.27
-19
10
Index không âm
0
1
2
3
4
Index âm
-5
-4
-3
-2
-1
Index không âm là các số nguyên không âm được đánh từ trái sang phải
(phần tử đầu tiên của list có index 0). Index âm là các số nguyên âm được
đánh từ phải sang trái (phần tử cuối cùng của list có index -1).
Để truy xuất phần tử trong list, ta dùng cú pháp sau:
ten_list[index]
ví dụ, để truy xuất phần tử 5.27 trong list1 ta dùng code sau:
list1[2]
hoặc
list1[-3]
Bạn có thể kết hợp với lệnh print để xem giá trị truy xuất được:
print(list1[2])
Ngoài ra, Python còn hỗ trợ truy xuất nhiều phần tử một lúc sử
dụng cú pháp sau (thường được gọi là cú pháp slicing):
ten_list[start_index : stop_index : step]
42
Trong đó start_index và stop_index là index phần tử đầu và index
phần tử cuối bạn muốn truy xuất, còn step là bước nhảy của index khi
chạy từ start_index đến stop_index. Các giá trị cho start_index,
stop_index, và step đều phải là số nguyên.
Lưu ý: Truy xuất slicing stop_index không bao gồm phần tử tại
stop_index. Do đó, để lấy được phần tử có index i ta cần phải dùng stop
index bằng i+1.
Ví dụ 3.6: Để lấy 3 phần tử đầu tiên của list1 ta dùng code sau:
list1[0:3:1]
hoặc dùng index âm:
list1[-5:-2:1]
Để lấy 3 phần tử cuối cùng của list1:
list1[2:5:1]
Trường hợp này nếu dùng index âm bạn sẽ không thể thu được kết
quả như mong muốn: list1[-3:0:1]. Lý do là index 0 là phần tử đầu
tiên của mảng, trong khi với step bằng 1 thì phép slicing sẽ lấy các phần
tử với index tăng dần, tức là lấy các phần tử theo chiều từ trái sang phải.
Quan sát list1 chúng ta có thể thấy không có cách nào đi từ trái sang
phải xuất phát từ phần tử có index -3 mà đến được phần tử có index 0.
Đối với trường hợp này, ta cần sử dụng giá trị mặc định của
start_index, stop_index, và step. Giá trị mặc định của các thành
phần sẽ được trình biên dịch Python sử dụng khi bạn để khuyết các thành
phần này trong lệnh slicing (xem ví dụ bên dưới).
▪ Giá trị mặc định của start_index là: 0
▪ Giá trị mặc định của stop_index sẽ lấy hết các phần tử đến cuối
mảng (nếu step có giá trị dương), hoặc lấy hết các phần tử đến đầu
mảng (nếu step có giá trị âm).
▪ Giá trị mặc định của step là: 1
Ví dụ, để lấy 3 phần tử cuối cùng của list1 ta có thể dùng slicing
với index âm như sau:
list1[-3::1]
do stop_index bị khuyết nên trình dịch Python sẽ lấy đến hết mảng theo
giá trị mặc định (để ý step bằng 1 là số dương). Ngoài ra, ta cũng có thể
43
bỏ step bằng 1 vì đây là giá trị mặc định. Code sau đây cho kết quả giống
với lệnh trên:
list1[-3:]
Tương tự, bạn có thể dùng code sau để lấy 3 phần tử đầu tiên của mảng:
list1[:3]
code trên bỏ qua start_index và step
Bên cạnh việc truy xuất các phần tử của list, Python cung cấp các
hàm sau để thao tác với list:
▪
▪
▪
Hàm append(): thêm phần tử vào cuối mảng. Ví dụ, để thêm phần
tử 48 vào list1 ta dùng code: list1.append(48).
Hàm insert(): chèn phần tử vào mảng. Hàm này yêu cầu 2 tham số
(arguments) là vị trí chèn (index chèn) và giá trị chèn. Ví dụ, để
thêm phần tử 90 vào list1 ở vị trí có index 2 ta dùng code:
list1.insert(2, 90).
Lệnh del: xóa phần tử hoặc xóa mảng. Ví dụ, để xóa phần tử ở vị
trí có index 5 ta dùng code: del list1[5]. Để xóa toàn bộ list1:
del list1.
Thực hành: Sử dụng các hàm trên với các list của bạn và in ra kết quả sau
khi thực thi. Tìm hiểu thêm hàm pop() với công dụng tương tự lệnh del.
Lưu ý: Trong Python còn cung cấp một dạng mảng tương tự như
list có tên là tuple. List và tuple có công năng và cách sử dụng giống nhau,
ngoại trừ việc tuple là một mảng hằng số, có nghĩa là khi tạo ra tuple, bạn
không thể thay đổi các phần tử của nó. Để tạo tuple ta dùng cú pháp sử
dụng dấu ngoặc đơn (thay cho ngoặc vuông của list):
tuple1 = (5, 3.14, -6, 7)
Thực hành: Nhập đoạn mã sau và đặt tên là list_demo.py Sau đó hãy thực
thi đoạn mã và cho biết kết quả in ra màn hình.
# declare lists
print('----declare lists')
numbers = []
a = [2, 7, 10, 8]
cities = ['Berlin', 'Seattle', 'Tokyo', 'Moscow']
44
b = [10, 3, 'Apple', 6, 'Strawberry']
c = range(1, 10, 2)
# print(lists
print('----print(lists')
print(a)
for city in cities:
print(city)
print(b)
print(c)
# get length of lists
print('----get length of lists')
print(len(a))
print(len(cities))
# add item into list
print('----add item')
numbers.append(10)
numbers.append(5)
cities.append('London')
for i in numbers:
print(i)
for city in cities:
print(city)
# get specific item
print('----get item')
print(cities[2])
print(a[3])
45
# sorting
print(a.sort())
# edit item
print('----edit item')
cities[2] = 'new city'
for city in cities:
print(city)
# remove item
print('----remove item')
a.remove(8) # by value
del cities[2] # by index
for city in cities:
print(city)
3.3 Vòng lặp for
Tương tự như vòng lặp while, vòng lặp for cũng có công dụng thực
thi lặp lại nhiều lần một khối lệnh. Tuy nhiên, trong Python, vòng lặp for
được thiết kế chủ yếu để làm việc với mảng hoặc các cấu trúc tương tự
mảng. Do đó, có thể nói vòng lặp while là vòng lặp đa dụng (mọi tác vụ
lặp đều có thể dùng vòng lặp này), còn vòng lặp for mang tính chuyên
dụng cho mảng.
Cú pháp của vòng lặp for:
for bien_chay in mang:
khoi_lenh_lap
khoi_lap_sau_for
Luồng hoạt động của vòng lặp for được mô tả trong lưu đồ ở Hình 3-2.
Trong cú pháp trên, for và in là các từ khóa, bien_chay là một biến
chứa các phần tử trong biến mang. Khi vòng lặp được thực thi, bien_chay
46
sẽ lần lượt chứa các phần tử trong mang. Ví dụ, nếu mang là một list có
các phần tử [2, 4, -6, 50] thì khối lệnh lặp sẽ được chạy 4 lần, mỗi lần chạy
thì bien_chay sẽ lần lượt có các giá trị 2, 4, -6 và 50. Sau khi chạy lặp 4
lần thì khoi_lap_sau_for sẽ được thực thi.
Hình 3-2 Lưu đồ hoạt động của vòng lặp for.
Ví dụ 3.7: Cho một list chứa các nhiệt độ tại nhiều thời điểm của một thiết
bị. Viết code để truy xuất các nhiệt độ âm chứa trong mảng.
#%% Xuất nhiệt độ âm
list_nhiet_do = [-2, -5, -8, 3, -1, 6, 0]
list_am = []
for phan_tu in list_nhiet_do:
if phan_tu<0:
list_am.append(phan_tu)
print(list_am)
47
Trong code trên, chúng ta khởi tạo list_am bằng một list rỗng (không
chứa phần tử nào). Khi chạy vòng lặp, các phần tử thỏa điều kiện (giá trị
âm) sẽ lần lược được thêm (append) vào list_am.
Thực hành: Thay đổi code trên để truy xuất các nhiệt độ nằm trong khoảng
từ 0 đến 10 độ.
Ví dụ 3.8: Cho một list chứa các nhiệt độ tại nhiều thời điểm của một thiết
bị. Viết code để xác định index của các nhiệt độ âm trong mảng.
#%% In index các phần tử âm
print('Indices cac phan tu am:')
for i in range(len(list_nhiet_do)):
if list_nhiet_do[i]<0:
print(i)
Để ý trong code trên chúng ta sử dụng hàm
range(len(list_nhiet_do)). Hàm này có công dụng tạo ra một
mảng chứa các index của list_nhiet_do, tức là list
[0,1,2,3,4,5,6] (vì list_nhiet_do có 7 phần tử). Khi thực thi,
biến i sẽ lần lượt chứa các phần tử của list index, tức là trong mỗi lần lặp,
biến i sẽ là index của một phần tử trong list_nhiet_do (lần lượt từ
trái sang phải).
Thực hành: Thay đổi code để lưu các phần tử âm vào một mảng (tương
tự ví dụ bên trên) và lưu index của các phần tử âm vào một mảng khác.
Thực hành: Nhập đoạn mã sau và đặt tên là for_demo.py. Sau đó hãy
thực thi đoạn mã và cho biết kết quả in ra màn hình.
# iteration - for
print('demo - iteration for')
for i in range(1, 5):
print(i)
# nested - for
print('demo - nested for')
48
for i in range(1, 3):
for j in range(5, 10):
print(str(i) + '-' + str(j))
3.4 Break, continue và pass
Từ khóa break có thể được sử dụng để dừng đoạn mã hoặc thoát
ra khỏi vòng lặp đang chứa break.
Ngược lại, từ khóa continue có thể được sử dụng để bỏ qua một
số phần mã phía sau continue để tiếp tục thực hiện vòng lặp mới.
Còn từ khóa pass đơn giản là một câu lệnh giả (câu lệnh không
làm gì cả). Pass có thể được dùng tại những vị trí mà cú pháp yêu cầu
phải có câu lệnh nhưng chương trình của chúng ta không có lệnh nào cần
làm ở đó.
Để minh họa, giả sử có đoạn mã sau, bằng cách sử dụng lệnh break
vòng lặp sẽ dừng khi giá trị value=7. Một trường hợp khác, vòng lặp có
thể tiếp tục thực hiện vòng lặp mới và có thể bỏ qua một số thành phần
trong thân vòng lặp khi sử dụng lệnh continue.
Thực hành: Nhập đoạn mã sau và đặt tên là break_continue_demo.py.
Sau đó hãy thực thi đoạn mã và cho biết kết quả in ra màn hình.
print('demo - break, continue and pass')
for i in range(1, 10):
if i == 4:
continue
if i == 7:
break
print(i)
pass # do nothing
print('This is the end of program')
49
Bài tập có lời giải
1. Viết chương trình tính chu vi của một đa giác. Chương trình sẽ đọc
các tọa độ x, y của các điểm trong một đa giác. Các tọa độ được
đọc liên tục cho đến khi người sử dụng nhập khoảng trắng ( ) đối
với tọa độ x. Mỗi khi đọc 1 tọa độ mới, chương trình sẽ tính toán
khoảng cách của điểm mới nhập so với điểm trước đó. Khi nhập
khoảng trắng vào trong tọa độ x thì chương trình sẽ thêm khoảng
cách từ điểm cuối đến điểm đầu để tính chu vi. Khi tính toán và
hiển thị chu vi thì các tọa độ của mỗi điểm đã nhập cũng được hiển
thị trên màn hình. Ví dụ có dạng như sau
2. Parity bit là một cơ chế đơn giản để phát hiện các lỗi trong việc
truyền dữ liệu thông qua một đường truyền không đáng tin cậy như
đường dây điện thoại. Ý tưởng rất đơn giản đó là một bit sẽ được
thêm vào và truyền đi sau mỗi một nhóm 8-bit dữ liệu. Vì thế một
bit lỗi trên đường truyền có thể được phát hiện dễ dàng. Bit parity
có thể được tính toán cho cả trường hợp parity là chẵn hoặc lẻ. Nếu
là parity chẵn thì tổng số bit 1 được truyền, gồm 8 bit dữ liệu và 1
bit parity phải là số chẵn. Ngược lại, khi chọn bit parity lẻ thì tổng
số bit 1 truyền đi sẽ là lẻ.
Viết chương trình tính bit parity của một nhóm 8 bit nhị phân được
nhập bởi người dùng sử dụng parity chẵn. Chương trình sẽ đọc
chuỗi nhị phân gồm 8 bit cho đến khi nhập khoảng trắng. Sau mỗi
chuỗi được nhập vào bởi người dùng, chương trình cần hiển thị một
thông điệp chỉ ra rằng người dùng muốn tính parity chẵn hay lẻ.
Một thông điệp cảnh báo sẽ được hiển thị nếu người dùng nhập
một chuỗi nhị phân có hơn 8 bit.
3. Viết chương trình thực hiện chuyển đổi số thập phân thành nhị
phân. Với số nguyên thập phân do người dùng nhập vào từ bàn
50
phím hãy sử dụng pháp chia được minh họa sau đây để thực hiện
việc chuyển đổi. Khi chương trình chuyển đổi được hoàn tất, kết
quả in ra màn hình sẽ chứa một chuỗi các bit nhị phân tương ứng
với số thập phân mà người dùng nhập.
Ban đầu cho chuỗi rỗng result
Cho q là thể hiện của số cần chuyển đổi
Repeat
Cho r bằng với phần dư của phép chia q với 2
Chuyển r thành chuối và cộng r với phần bắt đầu của result
Thực hiện chia q với 2, loại bỏ phần dư, và lưu phần nguyên của
phép chia vào chính q
Until q bằng 0
Bài tập thực hành
1. Sử dụng vòng lặp while tính các tổng sau, với n là một số nguyên
dương nhập bởi người dùng:
1
1
1
𝑆(𝑛) = 1 +
+
+ ⋯+
1+2 1+2+3
1 + 2 + ⋯+ 𝑛
1
1
1
𝑆(𝑛) =
+
+⋯+
1×2 2×3
𝑛 × (𝑛 + 1)
1 2 3
𝑛
𝑆(𝑛) = + + + ⋯ +
2 3 4
𝑛+1
1 3 5
2𝑛 + 1
𝑆(𝑛) = + + … +
2 4 6
2𝑛 + 2
2. Cho người dùng nhập số nguyên dương N. Nếu nhập sai thì cho
nhập lại đến khi đúng. Sau đó cho người dùng nhập N số nguyên
và in ra số lẻ lớn nhất trong những số được nhập. Cuối cùng, hỏi
người dùng có muốn tiếp tục không, nếu người dùng nhấn ‘c’ thì
tiếp tục, nhấn phím khác thì thoát chương trình.
3. In ra tất cả ước số của một số nguyên N nhập bởi người dùng.
4. Tính tổng các chữ số của số nguyên dương N nhập bởi người
dùng. Ví dụ: số N = 205 có tổng các chữ số là 2+0+5 = 8.
Gợi ý: với N = 257, ta có
257 % 10 = 7
int(257/10) = 25
51
5. Dùng vòng lặp for tính các tổng sau, với n nguyên dương nhập
bởi người dùng.
1
1
1
𝑆(𝑛) =
+
+⋯+
1×2 2×3
𝑛 × (𝑛 + 1)
1 3 5
2𝑛 + 1
𝑆(𝑛) = + + … +
2 4 6
2𝑛 + 2
6. Tạo một list có độ dài tùy ý chứa các phần tử tùy ý. Dùng vòng lặp
for tìm phần tử chia hết cho 5 lớn nhất trong list.
7. Tạo một list có độ dài tùy ý chứa các phần tử tùy ý. Dùng vòng lặp
for xóa các phần tử lớn hơn A trong list, với A là một số thực nhập
bởi người dùng.
Gợi ý: Có thể tạo list mới chứa phần tử không bị xóa. Nếu muốn
xóa bằng lệnh del thì cần dùng vòng lặp while.
8. Tạo một list có độ dài tùy ý chứa các phần tử đã sắp tăng dần.
Dùng vòng lặp for chèn một số B vào list sao cho list vẫn tăng dần,
với B là một số thực nhập bởi người dùng.
Gợi ý: dùng vòng lặp tìm ra vị trí (index) thích hợp cần chèn, sau
đó dùng hàm insert() để chèn B vào list. Có thể tìm hiểu từ khóa
break trong vòng lặp để sử dụng.
9. Tìm N số nguyên tố đầu tiên và lưu vào 1 list. N là một số nguyên
dương nhập bởi người dùng.
Yêu cầu: dùng vòng lặp for kết hợp với vòng lặp while.
10. Viết chương trình tính căn bậc hai của một số x. Sử dụng phương
pháp Newton để tính toán và hiển thị căn bậc hai của một số x được
nhập bởi người dùng. Thuật toán Newton như sau:
Đọc số x từ bàn phím
Khởi tạo guess bằng x/2
While guess không thỏa điều kiện do
Cập nhật giá trị guess bằng với trung bình của guess và x/guess.
Khi thuật toán chạy hoàn chỉnh thì guess chứa một giá trị xấp xỉ
với căn bậc hai của x, giá trị của phép xấp xỉ sẽ phụ thuộc vào điều
kiện thỏa mãn mà người dùng đặt. Trong bài tập này thì guess được
xem là thỏa mãn khi giá trị tuyệt đối của guess*guess so với x nhỏ
hơn hoặc bằng 10-12.
52
11. Viết chương trình thực hiện chuyển đổi một số nhị phân (binary)
sang hệ thập phân (decimal). Chương trình sẽ đọc một chuỗi các số
nhị phân. Sau đó, chương trình sẽ tính toán một số hệ thập phân
tương đương. Cuối cùng, chương trình sẽ hiển thị số thập phân
tương ứng lên màn hình.
53
Chương 4
NUMPY
Trong chương trước chúng ta đã tìm hiểu về list – một cấu trúc dữ
liệu cho phép lưu trữ mảng. List đơn giản và có đầy đủ chức năng cơ bản
của mảng. Tuy nhiên, khi chứa mảng số với nhiều phần tử, list có tốc độ
thực thi và hỗ trợ tính toán không bằng numpy arrays – một cấu trúc dữ
liệu dạng mảng của thư viện numpy.
4.1 Giới thiệu về Numpy1
NumPy (phát âm là /ˈnʌmpaɪ/) là một thư viện cho Python, hỗ trợ
làm việc với các mảng lớn, nhiều chiều, và cung cấp các hàm toán học cấp
cao hoạt động trên các mảng này. Phiên bản “tổ tiên” của NumPy:
Numeric, được tạo bởi Jim Hugunin và có sự đóng góp của một số nhà
phát triển khác. Năm 2005, Travis Oliphant tạo ra NumPy bằng cách kết
hợp các tính năng của Numarray vào Numeric với nhiều sửa đổi sâu rộng.
Hiện nay, NumPy là phần mềm mã nguồn mở và có nhiều người đóng góp
phát triển. NumPy là một dự án được tài trợ về mặt tài chính bởi
NumFOCUS.
4.2 Cài đặt thư viện numpy
Một trong những thế mạnh nổi trội của Python là hệ thống thư viện
(packages) mở đồ sộ của nó. Nếu biết cách sử dụng packages, việc lập
trình với Python sẽ trở nên dễ dàng hơn rất nhiều, vì các packages đã cài
đặt sẵn rất nhiều chức năng phục vụ đủ loại tác vụ mà chúng ta có thể làm
với máy tính.
Để sử dụng một package, trước tiên cần cài đặt nó. Đa số các thư
viện trong Python có thể cài đặt đơn giản như sau:
1
Nguồn: https://en.wikipedia.org/wiki/NumPy
54
1. Mở command prompt với quyền admin (nếu sử dụng hệ điều hành
Windows) hoặc terminal (nếu sử dụng Linux, MacOS).
2. Chạy lệnh:
pip install package_name
Trong đó package_name là tên của package bạn muốn cài đặt.
Ví dụ, để cài đặt numpy:
pip install numpy
Lưu ý: Lệnh này yêu cầu kết nối internet để tải thư viện về máy.
Để xem danh sách các thư viện đã được cài đặt trên máy tính, trong
cửa sổ command prompt hoặc terminal, bạn dùng lệnh: pip list.
Sau khi cài đặt thư viện xong, cần khai báo thư viện trước khi sử
dụng. Cú pháp như sau:
import ten_package as ten_viet_tat
Trong đó ten_package là tên thư viện cần dùng, còn ten_viet_tat là
một tên tùy ý được đặt để gọi thư viện cho tiện. Ví dụ:
import numpy as np
import matplotlib as mpl
Lưu ý: Cần phải cài đặt thư viện trước khi sử dụng, nếu không khi
chạy lệnh import sẽ báo lỗi không tìm thấy thư viện.
4.3 Numpy arrays
Numpy là một package chuyên hỗ trợ các tác vụ số học. Numpy
arrays là cấu trúc hỗ trợ mảng của thư viện numpy. Nó có nhiều tính năng
giống với list, như index, truy xuất phần tử, slicing. Trong phần này, chúng
ta sẽ nói về những điểm khác biệt của numpy arrays và lists.
Để tạo một numpy array ta dùng cú pháp sau:
ten_array = np.array(list)
Trong đó, list là tên một list hoặc một list tường minh. Xem ví dụ sau:
array1 = np.array([1, 4, 3, -6, 2, 4])
Lệnh trên tạo tra một numpy array có tên là array1 với các phần tử 1, 4,
3, -6, 2, 4.
Ví dụ khác:
list1 = [1, 4, 3, -6, 2, 4]
55
array2 = np.array(list1)
Code trên tạo tra một numpy array có tên là array2 với các phần tử của
list list1.
Lưu ý: Khác với list, numpy array các phần tử của numpy array chỉ
có 1 kiểu dữ liệu duy nhất. Ví dụ nếu trong array có các phần tử là kiểu số
nguyên và số thực thì tất cả các phần tử sẽ được tự động chuyển đổi thành
kiểu số thực. Điều này giúp các phép tính toán trên numpy array nhanh
hơn list vì dữ liệu có kiểu đồng nhất. Bạn cũng không cần quan tâm về
việc chuyển đổi kiểu dữ liệu, vì nó được numpy thực hiện một cách tự
động. Chúng ta chỉ cần biết sử dụng numpy array sẽ có tốc độ tính toán cải
hiện so với list đối với dữ liệu số và kích thước mảng lớn.
Việc truy xuất phần tử trong numpy array giống với list, tức là bạn
có thể dùng index không âm, index âm, slicing, ví dụ:
array1[2]
array1[-1]
array1[:3]
Để thêm, xóa các phần tử vào numpy array, ta dùng các hàm sau:
▪
▪
▪
append(): thêm phần tử vào cuối mảng. Cách gọi hàm này hơi
khác với append() trong list đôi chút.
Ví dụ: array1 = np.append(array1, 48)
(đối với list (xem mục 3.2) thì hàm append() được gọi đơn giản
hơn: list1.append(48))
insert(): chèn phần tử.
Ví dụ: array1 = np. insert(array1, 2, 90)
(code đối với list: list1.insert(2, 90))
delete(): xóa phần tử.
Ví dụ: array1 = np. delete(array1, 5)
(code đối với list: del list1[5])
Thư viện numpy cũng hỗ trợ các phép toán tương tự thư viện math,
nhưng phong phú và tốc độ thực thi nhanh hơn. Một số hàm tính toán của
numpy bao gồm1:
1
Xem danh sách đầy đủ tại https://numpy.org/doc/stable/reference/routines.math.html
56
▪
▪
▪
Các hàm tính toán: np.sqrt(), np.exp(), np.log(), np.cos(), …
Các hàm làm tròn: np.round(), np.floor(), np.ceil(), …
Các hàm tạo số ngẫu nhiên: np.random.randint(), np.random.rand()
Ngoài ra, numpy còn có các hàm hỗ trợ tạo mảng với các phần tử cách đều,
như np.arange(), np.linspace(). Ví dụ, code sau tạo ra một numpy array
chứa các số nguyên từ 2 đến 9:
np.arange(2,10,1)
Trong đó, tham số đầu tiên (số 2) là giá trị phần tử đầu tiên cần tạo, tham
số kế tiếp (số 10) là giá trị stop (phần tử cuối cùng được tạo luôn luôn nhỏ
hơn giá trị stop này), tham số cuối cùng (số 1) là bước nhảy.
Một ví dụ khác: để tạo ra một numpy array chứa các số lẻ từ 3 đến 15 ta
dùng code sau:
np.arange(3,16,2)
Để ý rằng step là 2, khi đó hàm arange sẽ tạo các số cách nhau 2 giá trị.
Hàm linspace() cũng có công dụng tương tự hàm arange() (tạo
mảng với các phần tử cách đều), tuy nhiên thay vì chỉ định bước nhảy, ta
chỉ định số lượng phần tử cần tạo. Ví dụ, lệnh sau sẽ tạo ra mảng bao gồm
4 phần tử cách đều nhau có giá trị từ 1 đến 20: [1, 5.75, 10.5, 15.25, 20]
np.linspace(1,20,5)
Ưu điểm của numpy array so với list là bên cạnh tốc độ thực thi nhanh,
numpy array còn hỗ trợ phép toán trên từng phần tử (element-wise
operations). Dạng phép toán không chỉ tăng tốc độ thực thi trên mảng kích
thước lớn mà còn cho phép viết code rất gọn gàng. Xem ví dụ sau.
Ví dụ 4.1: Cho mảng chứa cân nặng và mảng chứa chiều cao của một số
sinh viên. Hãy tính Body mass index (BMI) của các sinh viên này.
# Cách 1: sử dụng list
list_can_nang = [50, 62, 71, 55, 80]
list_chieu_cao = [1.65, 1.67, 1.8, 1.53, 1.7]
list_BMI = []
for i in range(0, len(list_can_nang)):
bmi = list_can_nang[i]/list_chieu_cao[i]**2
list_BMI.append(round(bmi,2))
57
print(list_BMI)
# Cách 2: sử dụng numpy array
arr_can_nang = np.array([50, 62, 71, 55, 80])
arr_chieu_cao = np.array([1.65, 1.67, 1.8, 1.53, 1.7])
arr_BMI = arr_can_nang/arr_chieu_cao**2
print(arr_BMI.round(2))
Có thể thấy code với numpy array ngắn gọn và trực quan hơn nhiều vì bạn
có thể viết code tính toán sử dụng trực tiếp tên mảng (không cần viết rõ
từng phần tử mảng). Ngoài ra, việc loại bỏ được vòng lặp giúp code thực
thi nhanh hơn.
Lưu ý: Để có thể sử dụng các pháp toán trên từng phần tử thì các
numpy array phải có kích thước giống nhau.
58
Bài tập thực hành
1. Tạo numpy array chứa các số lẻ từ 1 đến N, với N là số nguyên
dương nhập bởi người dùng.
Gợi ý: dùng hàm numpy.arange() (tương tự hàm range() của
Python. Sinh viên có thể dùng cú pháp ? hoặc google để biết thêm
thông tin về hàm).
2. Tạo numpy array chứa 20 số thực cách đều nhau thuộc khoảng
(a, b) với a, b nhập bởi người dùng.
Gợi ý: dùng hàm numpy.linspace() (có thể google cách dùng).
3. Tạo numpy array chứa 10 số thực ngẫu nhiên trong khoảng (a, b)
với a, b nhập bởi người dùng.
Gợi ý: dùng random.rand() (tạo số thực ngẫu nhiên trong [0,1)) và
cộng/trừ/nhân/chia với a, b để ra khoảng mong muốn.
4. Cho số lượng hàng hóa bán ra trong tuần của một cửa hàng được
lưu trong một mảng 2D có shape (2, 7), với mỗi dòng tương ứng
với buổi (sáng, chiều), và mỗi cột tương ứng với ngày trong tuần.
Sinh viên tự cho giá trị các phần tử (có thể dùng random.randint()).
Hãy viết chương trình cho biết:
a. Ngày bán được nhiều nhất tuần (theo tổng số hàng của cả 2
buổi). Gợi ý: dùng for trên cột.
b. Thời điểm bán được nhiều nhất (buổi nào, ngày nào). Gợi ý:
dùng for lồng nhau.
c. Buổi nào có khuynh hướng bán được nhiều hàng hơn. Ví dụ:
buổi sáng bán nhiều hơn buổi chiều trong 4 ngày thì kết luận buổi
sáng. Còn nếu buổi sáng bán nhiều buổi chiều trong 3 ngày, 1 ngày
bán bằng nhau, thì kết luận cả 2 buổi như nhau. Gợi ý: dùng for
lồng nhau.
59
Chương 5
SETS VÀ DICTIONARIES
Trong các chương trước, chúng ta đã được giới thiệu về cấu trúc
mảng (cài đặt bằng lists hoặc numpy arrays). Trong chương này, chúng ta
tìm hiểu về 2 cấu khác: sets (tập hợp) và dictionaries (cấu trúc dạng từ
điển). Các cấu trúc này cho phép tổ chức dữ liệu khác biệt hơn so với mảng.
Sets thì các phần tử không có thứ tự, không có index. Còn dictionaries thì
cho phép thiết lập index không phải số nguyên.
5.1 Sets
Cấu trúc dữ liệu sets (tập hợp) có thể chứa nhiều phần tử tương tự
như mảng. Nhưng khác với mảng, các phần tử của sets không có thứ tự
(tức là không thể đánh index). Cấu trúc này có thể coi là cài đặt của khái
niệm tập hợp trong toán học.
Để tạo ra một set, ta dùng cú pháp với dấu ngoặc nhọn như các ví
dụ sau:
set_1 = {3,3,2,2,4,5,6,2}
set_ho_ten = {'Tam', 'An', 'Hoa', 'Binh'}
set_diem = {'Tam', 10, 'An', 8, 'Hoa', 9.1, 'Binh',
5.4}
Tập hợp có 2 đặc tính: các phần tử không có thứ tự và không trùng lặp.
Thứ nhất, tập hợp không có thứ tự, vì vậy các phần tử không thể được đánh
index. Nói cách khác, bạn không thể truy xuất các phần tử trong tập hợp
bằng index như mảng.
Thực hành: Truy xuất phần tử trong set sử dụng index, ví dụ set_1[2].
Để lấy một phần tử ra khỏi tập hợp, ta làm cách gián tiếp như sau:
1. Kiểm tra xem phần tử có trong set không sử dụng từ khóa in.
2. Nếu có phần tử, thì dùng hàm remove() để xóa phần tử ra khỏi
set.
60
Code sau đây thực hiện 2 bước vừa mô tả:
phan_tu = 3
if phan_tu in set_1:
print('set_1 co chua phan tu',phan_tu)
set_1.remove(phan_tu)
else:
print(('set_1 khong chua phan tu',phan_tu))
Thực hành: Gọi hàm remove() với một phần tử không có trong set_1.
Thử in set_1 sau khi đã gọi hàm remove().
Đặc tính thứ hai của tập hợp là các phần tử không trùng lặp. Điều
này có nghĩa là nếu bạn đưa vào mảng nhiều phần tử giống nhau thì chỉ có
duy nhất một phần tử trong đó được giữ lại. Xem ví dụ sau:
set_1 = {3,3,2,2,4,5,6,2}
print(set_1)
Kết quả in ra của lệnh print(set_1) như sau: {2, 3, 4, 5, 6}.
Tức là chỉ có 1 phần tử 3, 1 phần tử 2 được giữ lại trong set_1.
Chúng ta có thể sử dụng đặc tính này của tập hợp để lọc lại các
phần tử khác nhau của một tập nào đó như các ví dụ sau.
Ví dụ 5.1: Cho một đoạn văn bản. Hãy xác định các chữ cái có trong đó.
text = "Mississippi river"
print(set(text))
Khi chạy đoạn code trên, bạn sẽ thấy các chữ cái cấu thành đoạn text bao
gồm: 'p', 'i', 'M', 'e', 's', 'v', ' ', 'r'. Để ý rằng
khoảng trắng cũng là một phần tử của tập hợp kết quả, ta có thể loại bỏ
nó ra bằng cách xử lý chuỗi (xem chương sau).
Ví dụ 5.2: Cho một danh sách người thực hiện một công việc nào đó. Danh
sách này lưu dưới dạng mảng: mỗi phần tử của mảng là tên của người thực
hiện trong một ngày (mỗi ngày có 1 người thực hiện). Hãy xác định số
người đã tham gia vào công việc này.
61
nhat_ky_cong_viec = ['Tam', 'An', 'Tam', 'Hoa', 'An',
'Binh', 'Tam', 'An', 'Tam']
nguoi_tham_gia = set(nhat_ky_cong_viec)
print('So luong nguoi tham gia:',len(nguoi_tham_gia))
Thực hành: Hãy xác định danh sách người tham gia trong 4 ngày đầu và
3 ngày cuối. Gợi ý: dùng slicing trên mảng danh sách người thực hiện.
Để thao tác với tập hợp, ta có thể dùng các hàm sau:
▪
▪
▪
add(): thêm một phần tử vào tập hợp. Ví dụ, set_1.add(9)
union(): tìm hợp 2 tập hợp. Ví dụ,
nhom1 = {'Tam', 'An'}
nhom2 = {'Hoa', 'Binh', 'Tam'}
danh_sach_tong_hop = nhom1.union(nhom2)
print(danh_sach_tong_hop)
intersection(): tìm giao của 2 tập hợp. Ví dụ,
ds_tham_gia_ca_2_nhom =
nhom1.intersection(nhom2)
print(ds_tham_gia_ca_2_nhom)
Thực hành: Sử dụng các hàm này trên tập hợp tùy ý và in kết quả sau khi
thực hiện. Tìm hiểu (google) và sử dụng hàm issubset() cũng như các hàm
khác của tập hợp.
5.2 Dictionaries
Dictionaries (cấu trúc dữ liệu dạng từ điển) là cấu trúc cho phép
chứa nhiều phần tử tương tự như mảng. Điểm khác biệt của dictionaries là
cho phép tạo index tùy ý. Đối với mảng, index luôn là số nguyên (số
nguyên âm hoặc không âm). Đối với dictionaries, bạn có thể tạo index
bằng số hoặc bằng chữ đều được, miễn là chúng phải khác biệt nhau cho
các phần tử (xem các ví dụ bên dưới).
Để tạo một dictionary ta dùng cú pháp với dấu ngoặc nhọn:
ten_dictinary = {index1: giatri1, index2: giatri2,
index3: giatri3}
Mỗi phần tử trong một dictionary là một bộ gồm hai phần: index
và giá trị, ngăn cách nhau bởi dấu hai chấm. Trong cú pháp trên chúng ta
62
tạo ra một dictionary có ba phần tử. Trong thực tế, số lượng phần tử là tùy
ý.
Ví dụ 5.3: Tạo một dictionary chứa tên các dụng cụ và số lượng tồn kho
của chúng.
#%% Tạo dictionary
kho_dung_cu = {'Vit': 3, 'May khoan': 2, 'Kem': 4,
'Bua': 1, 'May khoan': 1}
# Truy xuất phần tử:
print(kho_dung_cu['Kem'])
# Thay đổi giá trị phần tử:
kho_dung_cu['Kem'] = 3
# Thêm phần tử:
kho_dung_cu['Thang'] = 1
kho_dung_cu['Keo'] = 3
Trong ví dụ trên, biến kho_dung_cu là một dictionaries chứa 5 phần tử
tương ứng với tên dụng cụ (index) và số lượng của chúng (giá trị), ví dụ:
Vít có 3 cái, Máy khoan có 2 cái.
Để truy xuất một phần tử trong một dictionary chúng ta đặt index
trong dấu ngoặc vuông tương tự như với mảng, chỉ khác mảng ở chỗ index
của dictionary không nhất thiết là số nguyên. Ví dụ để truy xuất giá trị của
phần tử 'Kem' chúng ta dùng code: kho_dung_cu['Kem']. Để chỉnh
sửa giá trị cho phần tử, chúng ta đơn giản dừng phép gán sau khi truy xuất
phần tử, ví dụ lệnh sau đây sẽ thay đổi giá trị của phần tử 'Kem' thành
3: kho_dung_cu['Kem'] = 3.
Để thêm phần tử vào một dictionary, bạn viết code giống như truy
xuất một phần tử trong dictionary, nhưng sẽ đưa vào index mới chưa tồn
tại trong dictionary. Ví dụ, trong dictionary kho_dung_cu chưa có phần
tử với index 'Thang', khi đó bạn dùng lệnh sau để thêm phần tử 'Thang'
với số lượng 1 vào dictionary kho_dung_cu: kho_dung_cu['Thang']
= 1. Lưu ý rằng bạn phải gán giá trị cho phần tử mới, tức là bạn không thể
tạo ra một phần tử khuyết giá trị.
63
Lưu ý: Các index trong một dictionary không được trùng nhau,
tức là bạn không thể tạo một dictionary với nhiều phần tử có index giống
nhau. Lý do là index được sử dụng để truy xuất phần tử, nếu có nhiều
index giống nhau thì lệnh truy xuất phần tử sẽ không thể trả về một giá
trị duy nhất được.
Một lưu ý nữa là không chỉ index của các phần tử trong dictionary
có thể có kiểu dữ liệu là chữ hoặc số tùy ý, mà giá trị của các phần tử cũng
có thể có kiểu dữ liệu là chữ hoặc số tùy ý. Ví dụ:
thoi_khoa_bieu = {'Thu 2': 'Toan, Ve ky thuat', 'Thu
4': 'Xac suat thong ke', 'Thu 5:': 'Tin hoc, The chat'}
Code trên tạo ra một dictionary với index và giá trị đều có kiểu chữ (string).
Bạn cũng có thể tạo ra giá trị có cấu trúc mảng như ví dụ sau:
thoi_khoa_bieu = {'Thu 2': ['Toan', 'Ve ky thuat'],
'Thu 4': ['Xac suat thong ke'], 'Thu 5:': ['Tin hoc',
'The chat']}
Bên cạnh việc truy xuất phần tử bằng index, Python còn cung cấp một số
hàm giúp bạn làm việc với dictionary thuận tiện hơn.
▪
▪
▪
Hàm keys(): trả về các index trong dictionary.
Ví dụ: kho_dung_cu.keys()
Hàm values(): trả về các giá trị trong dictionary.
Ví dụ: kho_dung_cu.values()
Hàm items(): trả về các phần tử (bao gồm cả index và giá trị)
trong dictionary.
Ví dụ: kho_dung_cu.items()
Ví dụ sau sử dụng các hàm trên để lấy ra danh sách các dụng cụ có số
lượng từ 2 cái trở lên:
# Cách 1: dùng hàm keys()
ds_dung_cu_hon_2_cai = []
for ten in kho_dung_cu.keys():
if kho_dung_cu[ten]>=2:
ds_dung_cu_hon_2_cai.append(ten)
64
# Cách 2: dùng hàm items()
ds_dung_cu_hon_2_cai = []
for ten, so_luong in kho_dung_cu.items():
if so_luong>=2:
ds_dung_cu_hon_2_cai.append(ten)
Điểm khác biệt của hai cách trên là nếu dùng hàm keys() thì ta phải truy
xuất số lượng dụng cụ sử dụng index kho_dung_cu[ten]. Còn khi dùng
hàm items() thì số lượng dụng cụ đã được lấy sẵn đi kèm với index rồi.
Ví dụ 5.4: Cho một dictionary chứa bảng điểm của sinh viên, trong đó
index là tên sinh viên còn giá trị là một list chứa điểm các môn học của
sinh viên đó (xem code bên dưới). Hãy viết code thực hiện các chức năng
sau:
1. Thêm một cột điểm cho các sinh viên.
2. Tính điểm trung bình cho các sinh viên.
# Bảng điểm:
bang_diem = {'An': [9.5, 7.2, 8.6],
'Binh': [8.2, 9.1],
'Long': [5.4, 7.2, 8.3],
'Hoa': [6.1, 5.6, 7.7, 7.9]}
# 1. Thêm một cột điểm cho các sinh viên:
for ten in bang_diem.keys():
diem = float(input('Nhap diem cua '+ten))
bang_diem[ten].append(diem)
# 2. Tính điểm trung bình cho các sinh viên:
diem_tb = {}
for ten, list_diem in bang_diem.items():
diem_tb_1_sv = sum(list_diem)/len(list_diem)
diem_tb[ten] = round(diem_tb_1_sv,2)
Thực hành: Viết code tìm tên sinh viên có điểm trung bình lớn nhất (để
nhà trường trao học bổng chẳng hạn).
65
Thực hành: Nhập đoạn mã sau và đặt tên là dictionaries_demo.py Sau
đó hãy thực thi đoạn mã và cho biết kết quả in ra màn hình.
# declare
a = {}
b = {2: 'Sea', 3: 'River', 8: 'Mountain'}
c = {2: {4: 'abcd', 5: 'hjkl'}, 3: 'vbnm'}
d = dict(name='elena', age=30, roles=('manager',
'consultant'))
# print
print(a)
print(b)
print(c)
print(d)
# keys values
print(b.keys())
print(b.values())
print(b.items())
# add item
a.setdefault(2, 'car')
a.setdefault(5, 'train')
a.setdefault(7, 'plane')
print(a)
# check key
print(3 in b)
print(5 in b)
66
Bài tập có lời giải
1. Mã Morse là một sơ đồ mã hóa sử dụng dấu – và dấu . để thể hiện
các số và ký tự. Viết chương trình sử dụng dictionary để lưu trữ
bảng ánh xạ các ký tự này sang mã Morse. Bảng ánh xạ được thể
hiện dưới đây. Chương trình sẽ đọc một chuỗi từ người dùng sau
đó sẽ dịch chuỗi gồm các ký tự và số thành mã Morse, đặt thêm
các khoảng trắng giữa chuỗi các dấu gạch ngang – và dấu chấm .
Chương trình sẽ bỏ qua bất cứ ký tự nào không được liệt kê ở bảng dưới
đây. Dưới đây là mã Morse cho chuỗi Hello, World!
67
Bài tập thực hành
1. Đếm số lần xuất hiện của các chữ cái (không kể dấu câu, ví dụ: .
–) được dùng trong một câu, ví dụ:
“An eye for an eye makes the whole world blind. – Mahatma
Gandhi”1
Câu này có số lần xuất hiện của ‘A’: 1 lần, ‘a’: 6 lần, ‘b’: 1 lần...
Gợi ý: Có thể dùng set và dictionary kết hợp với vòng lặp để đếm
(dictionary dùng để lưu kết quả).
2. Tạo một chương trình quản lý thời gian trong ngày sử dụng
dictionary với keys là các loại hoạt động (ví dụ: Học, Ngủ, Thể
dục, Chơi, Di chuyển...) và values là thời gian (tính theo phút) của
hoạt động tương ứng. Chương trình cần thực hiện các chức năng
sau:
a. Nhập thêm thời gian: Hỏi người dùng nhập key hoạt động và số
phút rồi cộng dồn vào số phút đang có.
b. Thống kê thời gian các hoạt động (tính theo giờ), ví dụ: Học 8.4
giờ, Ngủ 7.2 giờ, Di chuyển 0.8 giờ...
c. Cho biết 2 hoạt động được làm nhiều nhất và 2 hoạt động làm ít
nhất trong ngày.
Mahatma Gandhi (1869 – 1948) là một lãnh tụ của Ấn Độ đã dẫn dắt đất nước với hơn
350 triệu dân (vào những năm 1940) thoát khỏi chế độ thực dân của Đế quốc Anh. Ông
nổi tiếng với phương pháp bất bạo lực (nonviolence) đã giúp Ấn Độ tránh được cuộc
chiến tranh thương vong lớn mà vẫn giành được độc lập. Ông là một trong những biểu
tượng toàn cầu của phong trào bất bạo lực.
1
Câu nói “An eye for an eye makes the whole world blind” (tạm dịch: Một con mắt đổi
một con mắt chỉ làm cả thế giới mù lòa) được cho là của ông Gandhi đã nói khi thuyết
phục nội các chính phủ Ấn Độ chọn con đường bất bạo lực để đối phó với Đế quốc Anh.
Trong bộ phim điện ảnh Gandhi (thắng 8 giải Oscars) kể về cuộc đời ông, câu nói này
nằm trong lời thoại: “An eye for an eye only ends up making the whole world blind”.
68
Chương 6
STRINGS
Các chương trước đã giới thiệu các các cấu trúc dữ liệu như mảng,
dictionaries với các phần tử chủ yếu có kiểu dữ liệu dạng số (số nguyên,
số thực). Trong chương này, chúng ta tìm hiểu về kiểu dữ liệu chuỗi
(strings) dành cho chữ (text).
6.1 Khái niệm và khởi tạo strings
Kiểu dữ liệu string (thường được dịch là chuỗi) là kiểu dữ liệu phục
vụ lưu trữ chữ (text). Một cách đơn giản, một chuỗi là một tuple (xem mục
3.2) của các ký tự (characters).
Để tạo 1 string bạn dùng cú pháp với dấu nháy đơn hoặc nháy kép:
ten_string = 'noi dung string'
ten_string = "noi dung string"
Cả hai cú pháp trên hoàn toàn tương đương nhau. Lưu ý rằng các
strings tạo bởi cú pháp trên chỉ chứa text nằm trên một dòng. Để tạo string
có nội dung nằm trên nhiều dòng các bạn dùng cú pháp với 3 dấu nháy đơn
liên tiếp:
ten_string = '''Dong 1.
Dong 2. '''
Ví dụ 6.1:
str1 = 'Hom nay la thu ba.'
ho_ten = 'Tran Nhan Tong'
bai_tho = '''Công cha như núi Thái Sơn,
Nghĩa mẹ như nước trong nguồn chảy ra.
Một lòng thờ mẹ kính cha,
Cho tròn chữ hiếu mới là đạo con.'''
Bởi vì string là một tuple của các ký tự nên bạn có thể truy xuất các ký tự
của nó giống như cách truy xuất các phần tử của tuple. Ví dụ:
69
print(ho_ten[2])
print(bai_tho[5:8])
for char in ho_ten:
print(char)
Lưu ý: Như trình bày trong mục 3.2, tuple là kiểu mảng hằng số,
tức là các phần tử của tuple không thể bị thay đổi sau khi tuple được khởi
tạo. Vì vậy, bạn không thể thay đổi các ký tự trong string bằng phép gán
như với mảng. Đây là điểm khác biệt của kiểu string trong Python với các
ngôn ngữ khác, như C, C++.
Bạn có thể kết hợp 2 string để tạo string mới bằng cú pháp với dấu
cộng:
ho = 'Trần'
ten = 'Hiếu Nhân'
ho_ten = ho + ten
print(ho_ten)
Thực hành: Thử chạy code sau và giải thích kết quả khác biệt với code
bên trên. Lưu ý ' ' là một string chứa khoảng trắng (ở giữa 2 dấu nháy
đơn có 1 khoảng trắng).
ho_ten = ho + ' ' + ten
print(ho_ten)
Ví dụ 6.2: Đếm số lần xuất hiện của các ký tự trong 1 string. Yêu cầu: chỉ
đếm ký tự trong bảng chữ cái tiếng Anh.
quote = 'An eye for an eye makes the whole world blind.
- Mahatma Gandhi'
char_count = {}
for char in quote:
if 'A'<=char<='Z' or 'a'<=char<='z':
if char in char_count.keys():
char_count[char] += 1
else:
char_count[char] = 1
print(char_count)
70
Thực hành: Đọc hiểu và giải thích hoạt động của đoạn code trên.
Gợi ý: Bạn hãy nhớ lại cách tạo mới và cập nhật giá trị các phần tử trong
một dictionary.
Ví dụ 6.3: Đếm số từ (word) trong 1 string. Gợi ý: một từ luôn được bắt
đầu bằng một khoảng trắng và sau đó là một ký tự.
dem = 0
for i in range(len(str1)-1):
if (str1[i]==' ') and (str1[i+1]!=' '):
dem += 1
if str1[0]!=' ':
dem += 1
6.2 Hàm xử lý strings
Bên cạnh việc truy xuất các ký tự trong string bằng index (như
tuple), Python còn hỗ trợ một số hàm để làm việc với string như sau:
▪ Hàm split(): tách string thành một list các phần tử dựa theo ký tự
phân cách (separator, mặc định là khoảng trắng).
Ví dụ: list_words = ho_ten.split()
▪ Hàm strip(): xóa khoảng trắng ở đầu và cuối string.
Ví dụ: bai_tho = bai_tho.strip()
▪ Hàm replace(): thay thế một string con trong string.
Ví dụ: str1 = str1.replace('ba', 'tu')
▪ Hàm isdigit(): trả về True nếu tất cả ký tự trong string là chữ số.
Ví dụ: so_dien_thoai.isdigit()
Tham khảo thêm các hàm xử lý khác tại
https://www.w3schools.com/python/python_ref_string.asp
Ví dụ 6.4: Đếm số từ (word) trong 1 string.
list_words = str1.split()
no_of_words = len(list_words)
Ví dụ 6.5: Trích xuất mã OTP từ tin nhắn.
tin_nhan = 'Ma OTP cua ban la 12583'
list_tu = tin_nhan.split()
OTP = ''
for tu in list_tu:
if tu.isdigit() == True:
OTP = tu
print('Ma OTP:', OTP)
71
Thực hành: Trích xuất mã OTP trong tin nhắn sau:
tin_nhan = 'Ma OTP cua ban la 12583 (ma co hieu luc
trong 120 giay).'
Gợi ý: OTP là đoạn số có chiều dài 5 chữ số.
Thực hành: Trích xuất mã OTP trong tin nhắn sau:
tin_nhan = 'Ma OTP cua ban la "12583". Ma co hieu luc
trong 120 giay.'
Gợi ý: Bạn có thể dùng code sau để xóa các ký tự đặc biệt như dấu câu
trước khi dùng hàm split() để tách từ.
list_dau = ['.', '"', '?', ',', '!']
for char in list_dau:
if char in tin_nhan:
tin_nhan = tin_nhan.replace(char, '')
Lưu ý: đoạn code '' là một chuỗi rỗng (không chức bất cứ ký tự
hay khoảng trắng nào).
Ví dụ 6.6: Viết hoa chữ cái đầu từ trong một string. Lưu ý rằng bạn không
thể thay đổi các ký tự trong một string. Vì vậy chúng ta sẽ chuyển đổi
string thành list các ký tự bằng hàm list() để chỉnh sửa các ký tự. Sau đó
sẽ chuyển đổi list trở lại thành string bằng hàm join().
ten = 'daI HOc su phAm ky tHUat'
ten = ten.lower()
list_ten = list(ten) # chuyển string thành list
for i in range(len(list_ten)-1):
if list_ten[i]==' ' and list_ten[i+1]!=' ':
list_ten[i+1] = list_ten[i+1].upper()
list_ten[0] = list_ten[0].upper()
ten = ''.join(list_ten) # chuyển list thành string
print(ten)
72
Bài tập thực hành
1. Đếm số lần xuất hiện của các từ trong một string (không phân biệt
hoa thường).
Ví dụ: câu “An eye for an eye makes the whole world blind –
Mahatma Gandhi” có 2 từ ‘an’, 2 từ ‘eye’, 1 từ ‘for’...
Gợi ý: Đổi string thành chữ thường (lower()) và dùng dictionary
chứa các từ và số lần xuất hiện của chúng.
2. Kiểm tra một password có mạnh không, biết rằng password được
xem là mạnh nếu nó có dài tối thiểu là 8 và có chứa: chữ cái, chữ
số, ký tự đặc biệt (không phải chữ cái và chữ số, ví dụ #%@).
Ví dụ: ‘SPKT1122@’ là password mạnh; ‘123456789’,
‘spkttpchm’ hoặc ‘#$#&*^#*($’ không phải là passwords mạnh.
3. Tạo password ngẫu nhiên là một password như mô tả trong câu
trên.
Gợi ý: Tạo ra một số nguyên ngẫu nhiên nằm trong khoảng giá trị
ASCII của chữ cái, chữ số, ký tự đặc biệt, rồi chuyển mã ASCII
thành ký tự bằng hàm chr().
4. Tìm hiểu hàm title() và hàm translate(): nêu công dụng và viết code
minh họa.
73
Chương 7
HÀM
Trong các chương trước, chúng ta đã tìm hiểu qua nhiều thành phần
cơ bản của ngôn ngữ lập trình Python. Với những hiểu biết này, bạn có
thể lập trình xử lý nhiều công việc khác nhau. Tuy nhiên, khi chương
trình trở nên phức tạp, có nhiều đoạn code bạn cần phải dùng đi dùng
lại nhiều lần. Lúc này, hàm chính là công cụ giúp bạn xử lý việc tái sử
dụng code hiệu quả.
7.1 Khái niệm và cú pháp
Khi viết một chương trình lớn, sẽ có nhiều đoạn code bạn cần phải
dùng đi dùng lại nhiều lần. Nếu bạn copy các đoạn code này một cách thủ
công sẽ gây ra một số vấn đề chương trình của bạn như:
▪
▪
Code trở nên dài, khó đọc hơn.
Nếu đoạn code được copy có lỗi hoặc cần chỉnh sửa, bạn sẽ mất
thời gian dò lại tất cả các chỗ đã copy để chỉnh sửa.
Điều này làm cho chương trình của bạn khó đọc, dễ mắc lỗi và khó
bảo trì, nâng cấp. Lúc này, hàm chính là công cụ giúp bạn xử lý việc tái sử
dụng code hiệu quả.
Nói một cách đơn giản, hàm là một đoạn code được đặt tên. Khi
đó, bạn chỉ việc gọi tên của nó khi muốn sử dụng đoạn code đó. Có hai
loại hàm trong lập trình:
▪
▪
74
Hàm có sẵn (built-in functions): đây là những hàm đã được viết sẵn
trong Python hoặc các thư viện. Ví dụ: print(), input(),
numpy.array(), str1.isdigit(). Để xem thông tin về các hàm này bạn
dùng cú pháp với dấu chấm hỏi, ví dụ numpy.array? hoặc bạn có
thể google chúng.
Hàm tự viết (user-defined functions): đây là hàm do bạn tự viết ra
để phục vụ cho chương trình của bạn. Chương này sẽ tập trung vào
dạng hàm này.
Để viết hàm, bạn dùng cú pháp sau:
def ten_ham(tham_so1, tham_so2, tham_so3):
'''
Thông tin mô tả hàm
'''
# Các dòng lệnh của hàm đặt ở đây
return gia_tri1, gia_tri2
Trong cú pháp trên, def và return là các từ khóa. Theo sau tên hàm
ten_ham là danh sách các tham số (các giá trị đầu vào của hàm). Trong
cú pháp trên liệt kê 3 tham số, nhưng số lượng tham số là tùy ý. Bên trong
thân hàm phần đầu tiên là thông tin mô tả hàm đặt trong cặp 3 dấu nháy
đơn. Phần này là tùy chọn. Thông thường phần này sẽ mô tả các tham số
đầu vào và giá trị trả về của hàm.
Bên dưới phần mô tả là các dòng lệnh của hàm. Phần cuối cùng là dòng
return. Đây là nơi liệt kê các giá trị trả về của hàm. Số lượng giá trị trả về
là tùy ý (trong cú pháp trên liệt kê 2 giá trị trả về).
Lưu ý: Có hai kinh nghiệm tuy đơn giản nhưng hiệu quả giúp hàm
của bạn dễ viết, dễ bảo trì, nâng cấp hơn:
1. Tên hàm nên dễ hiểu. Đừng ngại một tên hàm dài, hãy ngại một
tên hàm khó hiểu. Ví dụ: thay vì đặt tên hàm s(), gpt(), min(), bạn
hãy đặt tên: TinhDienTich(), GiaiPhuongTrinh(),
TimSoNhoNhat().
2. Mỗi hàm chỉ thực hiện một việc. Thay vì viết một hàm lớn nhiều
chức năng, ta nên viết nhiều hàm nhỏ: mỗi hàm thực hiện một việc.
Điều này giúp các hàm ngắn gọn, dễ sửa lỗi (nếu có). Ví dụ: thay
vì viết hàm TimSoNhoNhatVaSapXepMang(), ta nên viết thành 2
hàm: TimSoNhoNhat() và SapXepMang().
Để gọi hàm, bạn chỉ cần ghi tên hàm và đưa vào các tham số:
gia_tri_tra_ve = ten_ham(tham_so1, tham_so2, tham_so)
Đừng lo lắng nếu cảm thấy cú pháp hàm khó hiểu. Đây là điều bình thường
nếu bạn chưa bao giờ viết hàm. Hãy xem qua một số ví dụ sau và thực
hành viết hàm, bạn sẽ dần hiểu rõ và sử dụng hàm dễ dàng hơn.
75
7.2 Một số ví dụ
Ví dụ 7.1: Viết hàm in ra phí ship với tham số là độ dài quãng đường.
def TinhPhiShip(quang_duong):
'''
Ham tinh va in ra thong bao phi ship theo cong
thuc: quang_duong (km) * 5000 (dong).
Input: quang duong (km)
Output: [khong co]
'''
phi_ship = quang_duong*5000
print('Phi ship la:', phi_ship)
TinhPhiShip(5)
Trong ví dụ trên, để ý tên hàm TinhPhiShip() được đặt dễ hiểu (nên tránh
những tên như: TPS(), ship(), phi() vì chúng khó hiểu). Hàm TinhPhiShip()
nhận vào 1 tham số duy nhất quang_duong và không trả về (return) giá
trị nào cả. Nó chỉ in ra kết quả tính toán bằng lệnh print(), nên khi bạn gọi
hàm này sẽ nhận được thông báo: 'Phi ship la: …'
Ví dụ 7.2: Viết hàm tính diện tích hình chữ nhật. Hàm nhận vào 2 tham số
là chiều rộng và chiều dài của hình chữ nhật
def DienTichHinhChuNhat(dai, rong):
'''
Ham in ra dien tich hinh chu nhat.
Input: do dai va do rong
Output: [khong co]
'''
dien_tich = dai*rong
print('Dien tich hinh chu nhat:', dien_tich)
DienTichHinhChuNhat(5, 20)
76
Hàm trên cũng không trả về giá trị nào. Nhưng khác với hàm
TinhPhiShip() ở chỗ hàm này yêu cầu 2 tham số đầu vào. Nếu bạn chỉ
truyền vào 1 tham số thì khi gọi hàm sẽ bị báo lỗi thiếu tham số.
Ví dụ 7.3: Viết hàm tính diện tích hình tròn. Yêu cầu: trả về (return) diện
tích hình tròn.
def DienTichTron(ban_kinh):
'''
Ham tra ve dien tich hinh tron.
Input: ban kinh
Output: dien tich
'''
import math
dien_tich = math.pi * ban_kinh**2
return dien_tich
area = DienTichTron(5)
print('Dien tich hinh tron:', area)
Hàm trên nhận vào 1 tham số. Điểm khác biệt của nó so với các ví dụ trước
là nó trả về (return) giá trị. Khi đó, lúc gọi hàm bạn cần có một biến để lưu
lại giá trị trả về của hàm (trong ví dụ trên là biến area).
Thực hành: Viết lại hàm DienTichHinhChuNhat() trả về diện tích
hình chữ nhật.
Ví dụ 7.4: Viết hàm tính diện tích của nhiều hình tròn. Hàm này nhận vào
1 tham số là 1 list chứa các bán kính của các hình tròn cần tính.
def DienTichNhieuHinhTron(list_ban_kinh):
'''
Ham tra ve list dien tich cua nhieu hinh tron.
Input: list cac ban kinh
Output: list cac dien tich
'''
import numpy as np
list_dien_tich = np.zeros(len(list_ban_kinh))
for i in range(len(list_ban_kinh)):
77
dien_tich = DienTichTron(list_ban_kinh[i])
list_dien_tich[i] = round(dien_tich,2)
return list_dien_tich
list_dien_tich = DienTichNhieuHinhTron([4, 2, 1, 7])
print('Dien tich cac hinh tron:', list_dien_tich)
Trong code trên chúng ta sử dụng hàm np.zeros() để khởi tạo
list_dien_tich: một numpy array chứa toàn phần tử là số 0, số lượng
phần tử của list_dien_tich bằng với kích thước list_ban_kinh.
Bạn có thể sử dụng cách này để khởi tạo mảng khi biết trước số lượng
phần tử. Cách làm này giúp code hoạt động hiệu quả hơn.
Để ý trong hàm trên chúng ta gọi hàm DienTichTron() để tính diện tích
của 1 hình tròn. Nói cách khác, bạn có thể tùy ý gọi các hàm tự viết bên
trong một hàm tự viết khác.
Ví dụ 7.5: Cho một list các nhiệt độ thu được bằng cảm biến trong 1 thiết
bị. Viết hàm nhận vào 1 tham số là list các nhiệt độ và trả về các nhiệt độ
cao hơn 70 độ C.
def LocNhietDoCao(list_temp):
'''
Ham tra ve list cac nhiet do > 70.
Input: list cac nhiet do
Output: list cac nhiet do cao
'''
list_high_temp = []
for temp in list_temp:
if temp > 70:
list_high_temp.append(temp)
return list_high_temp
list_nhiet_do = [48, 56, 72, 81, 64, 53, 78]
print('Cac nhiet do cao:',
LocNhietDoCao(list_nhiet_do))
78
Thực hành: Sửa hàm trên để trả về nhiệt độ lớn hơn một ngưỡng bất kỳ
(thay vì cố định là 70 độ C). Ngưỡng này là 1 tham số của hàm.
Ví dụ 7.6: Cho một list các nhiệt độ thu được bằng cảm biến trong một
thiết bị. Cứ mỗi phút thì ghi nhận một nhiệt độ. Viết hàm trả về những
nhiệt độ lớn hơn 70 độ C và thời điểm (phút) xuất hiện những nhiệt độ này.
Gợi ý: Mỗi phút ghi nhận một nhiệt độ tức là mỗi phút sẽ có 1 phần tử
trong list nhiệt độ. Hay nói cách khác, index của các phần tử chính là thời
điểm chúng được ghi nhận (index 0, 1, 2… tương ứng với phút thứ 0, 1,
3…).
def LocNhietDoCao(list_temp):
'''
Ham tra ve list nhiet do va indices cua cac nhiet
do > 70.
Input: list cac nhiet do
Output: list nhiet do va ids cac nhiet do cao
'''
list_high_temp = []
list_ids_high_temp = []
for i in range(len(list_temp)):
if list_temp[i] > 70:
list_ids_high_temp.append(i)
list_high_temp.append(list_temp[i])
return list_high_temp, list_ids_high_temp
list_nhiet_do = [48, 56, 72, 81, 64, 53, 78]
list_temp, list_ids = LocNhietDoCao(list_nhiet_do)
print('Cac nhiet do cao:', list_temp)
print('Cac ids nhiet do cao:', list_ids)
Để ý rằng hàm LocNhietDoCao() trả về hai giá trị: list_high_temp,
list_ids_high_temp. Vì vậy khi gọi hàm chúng ta cũng cần có hai
biến để lưu giá trị trả về (trong code trên ta dùng hai biến list_temp,
list_ids). Các biến nhận giá trị trả về không nhất thiết phải cùng tên với
biến ở dòng return trong hàm.
79
Thực hành: Chỉnh sửa hàm trên để trả về thời điểm xuất hiện các nhiệt độ
nằm trong khoảng [temp_min, temp_max] với temp_min, temp_max là
các tham số của hàm. Ví dụ temp_min = 50, temp_max = 80: hàm sẽ trả
về index của các nhiệt độ nằm trong khoảng [50, 80].
Thực hành: Nhập đoạn mã sau và đặt tên là defined_function_demo.py.
Sau đó hãy thực thi đoạn mã và cho biết kết quả in ra màn hình.
def foo():
print('foo()')
def calculate(val_a, val_b):
val = val_a * val_b
return val
def perform(num):
d = num * 5
return d, d + 5, d - 2
def fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return fibonacci(n-1) + fibonacci(n-2)
foo()
m = calculate(10, 5)
print(m)
a, b, c = perform(5)
print(a)
print(b)
print(c)
res = fibonacci(10)
print(res)
80
7.3 Biến đoạn code bất kỳ thành hàm
Để biến một đoạn code bất kỳ thành hàm bạn cần xác định:
▪
▪
Đầu vào của đoạn code này
Giá trị trả về của đoạn code này
Khi đó, bạn chỉ việc đưa chuyển các biến chứa đầu vào của đoạn code
thành các tham số của hàm. Còn giá trị trả về thì sẽ đặt ở dòng return
của hàm.
Ví dụ 7.7: Cho đoạn code kiểm tra số N có phải số nguyên số không
như sau.
N = 7
i = 2
la_nguyen_to = True
while i <= N/2:
if N%i == 0:
la_nguyen_to = False
break
i += 1
if la_nguyen_to:
print(N, 'la so nguyen to.')
else:
print(N, 'khong phai so nguyen to.')
Để biến code này thành một hàm kiểm tra số nguyên tố, ta để ý rằng
biến N là đầu vào còn biến la_nguyen_to là đầu ra. Vì vậy chúng ta có
thể biến đoạn code thành hàm như sau:
def CheckPrime(N):
'''
Ham kiem tra so nguyen duong N co phai so nguyen
to khong.
Input: so nguyen duong N
Output: True neu N la so nguyen to, False neu nguoc
lai.
'''
i = 2
la_nguyen_to = True
while i <= N/2:
81
if N%i == 0:
la_nguyen_to = False
break
i += 1
return la_nguyen_to
ket_qua = CheckPrime(7)
if ket_qua:
print(N, 'la so nguyen to.')
else:
print(N, 'khong phai so nguyen to.')
Ví dụ 7.8: Cho đoạn code truy xuất mã OTP trong một tin nhắn. Hãy biến
code này thành một hàm trích mã OTP từ tin nhắn.
tin_nhan = 'Ma OTP cua ban la 46457 (ma co hieu luc
trong 2 phut).'
list_tu = tin_nhan.split()
OTP = ''
for tu in list_tu:
if tu.isdigit() == True and len(tu)==5:
OTP = tu
print('Ma OTP:', OTP)
Trong đoạn code trên, biến tin_nhan là đầu vào, còn biến OTP là đầu
ra. Vì vậy ta có thể biến nó thành hàm như sau.
def GetOTP(tin_nhan):
list_tu = tin_nhan.split()
OTP = ''
for tu in list_tu:
if tu.isdigit() == True and len(tu)==5:
OTP = tu
return OTP
tin_nhan = 'Ma OTP cua ban la 46457 (ma co hieu luc
trong 2 phut).'
maOTP = GetOTP(tin_nhan)
print('Ma OTP:', maOTP)
82
Bài tập có lời giải
1. Viết chương trình tính giá tiền dịch vụ taxi. Giá thành dịch vụ taxi
bao gồm chi phí cơ sở là 4USD và cộng thêm 0.25USD cho mỗi
140m di chuyển. Viết một chương trình có đầu vào là quãng
đường di chuyển (tính theo km) sau đó trả về giá dịch vụ cho
quãng đường đó. Viết một chương trình chính (main) để minh
họa hàm vừa xây dựng. Lưu ý: vì giá vé có thể thay đổi, hãy định
nghĩa một hằng số qui định giá cơ sở để có thể linh hoạt cho các
trường hợp giá thành tăng.
2. Viết chương trình tính trung vị của 3 điểm. Hãy định nghĩa một
hàm nhận 3 tham số ngõ vào và trả về kết quả là trung vị của các
điểm đã nhận. Viết chương trình chính (main) để đọc 3 giá trị này
từ người dùng và hiển thị kết quả lên màn hình.
3. Số nguyên tố là số nguyên lớn hơn 1 và chỉ chia hết cho 1 và chính
số đó. Viết một hàm với chức năng là kiểm tra xem tham số đầu
vào của hàm đó có phải là số nguyên tố không. Hàm này sẽ tính
toán và trả về True nếu đó là số nguyên tố và ngược lại thì trả về
False. Viết chương trình chính (main) để đọc một số nguyên từ
người dùng và hiển thị thông điệp chỉ ra số vừa nhập có phải là số
nguyên tố không.
4. Định nghĩa một hàm nextPrime nhằm tìm và trả về kết quả là số
nguyên tố xuất hiện đầu tiên mà lớn hơn số n. Giá trị số n sẽ được
gán như là tham số ngõ vào duy nhất của hàm. Viết chương trình
chính (main) để đọc một số nguyên từ người dùng và hiển thị số
nguyên tố đầu tiên và lớn hơn số người dùng vừa nhập.
5. Viết chương trình kiểm tra xem mật khẩu được khai báo là đạt tính
bảo mật cao hay không? Mật khẩu được định nghĩa là có tính bảo
mật cao khi có ít nhất 8 ký tự đối với độ dài, chứa ít nhất 1 ký tự
viết thường, một ký tự viết hoa, và một con số. Định nghĩa một
hàm kiểm tra mật khẩu và hàm này sẽ trả về True nếu mật khẩu
thỏa các điều kiện ở trên. Ngược lại thì hàm sẽ trả về False. Viết
chương trình chính (main) để đọc mật khẩu từ người dùng và thông
báo mật khẩu đó có tính bảo mật cao hay không.
83
6. Viết chương trình cho phép người dùng có thể chuyển đổi giá trị
giữa các hệ thống số như hệ 2, hệ 10 và hệ 16. Nếu người dùng lựa
chọn hệ thống số không phù hợp với các hệ mà chương trình hỗ trợ
thì chương trình sẽ in ra 1 dòng thông báo. Hãy định nghĩa một số
hàm chức năng khác nhau để thực hiện chuyển đổi giá trị từ sang
hệ thập phân, và hệ thập phân sang nhị phân hoặc thập lục. Chương
trình chính (main) sẽ đọc các hệ cơ bản và giá trị số muốn chuyển
đổi từ người sử dụng.
Bài tập thực hành
1. Viết hàm nhận vào một tham số là điện năng tiêu thụ mỗi ngày của
một thiết bị. Hàm kiểm tra thiết bị này có tiết kiệm điện hay không
và in ra thông báo. Biết rằng nếu điện năng tiêu thụ mỗi ngày < 10
kWh được gọi là tiết kiệm.
2. Viết hàm nhận vào một tham số là điện năng tiêu thụ mỗi ngày của
một thiết bị. Hàm trả về số sao tiết kiệm năng lượng của thiết bị,
với số sao tiết kiệm được quy định như sau:
Điện năng tiêu thụ
P (kWh)
Số sao tiết kiệm
năng lượng
P<2
5
2≤P<4
4
4≤P<6
3
6 ≤ P < 10
2
P ≥ 10
1
3. Viết hàm nhận vào một tham số là điện năng tiêu thụ mỗi ngày của
một thiết bị. Hàm in ra thông báo thiết bị có tiết kiệm điện không.
Yêu cầu: hàm này gọi hàm trong câu 2 để tính số sao tiết kiệm.
Thiết bị có số sao nhỏ hơn 3 được gọi là không tiết kiệm điện.
84
4. Viết hàm nhận vào hai tham số: một list chứa tốc độ quay của một
động cơ nào đó (list số nguyên), và một giá trị min. Hàm trả về list
các tốc độ quay nhỏ hơn min và indices của các tốc độ này.
5. Viết hàm giải phương trình bậc hai a𝑥 2 + 𝑏𝑥 + 𝑐 = 0, với a, b, c
là các tham số của hàm. Hàm trả về list chứa các nghiệm (list rỗng
nếu vô nghiệm).
6. Viết hàm tính cos(x) bằng Taylor series.
Gợi ý: sử dụng vòng lặp while (xem nội dung tuần 3).
Công thức khai triển Taylor của cos(x) xem tại:
https://en.wikipedia.org/wiki/Taylor_series#Trigonometric_functi
ons
7. Biến đoạn code viết hoa các chữ cái đầu từ trong tuần 7 thành một
hàm nhận vào một string và trả về một string đã được viết hoa các
chữ cái đầu từ. Ví dụ: “nGuyeN hiEu NGhiA” → “Nguyen Hieu
Nghia”.
85
Chương 8
LỖI VÀ SỬA LỖI
Khi học đến đây thì gần như chúng ta đã nắm đủ các thành phần
căn bản của Python để có thể tự phát triển các chương trình từ đơn giản
đến tương đối phức tạp. Vấn đề phát sinh là có thể xảy ra lỗi (bugs) làm
chương trình bị đổ vỡ (crashed) hoặc hoạt động không chính xác như mong
muốn của chúng ta. Khi đó, hiểu được các dạng lỗi và cách gỡ lỗi (debug)
trở nên vô cùng cần thiết.
8.1 Các dạng lỗi trong lập trình
Các lỗi trong lập trình thường được chia thành ba loại chính:
▪
Lỗi cú pháp (syntax errors): đây là dạng lỗi dễ xử lý nhất. Khi bạn
viết code sai cú pháp, ví dụ thụt đầu dòng không thẳng hàng, thiếu
dấu đóng ngoặc… thì sẽ tạo ra lỗi này. Dạng lỗi này được đa số các
IDE, editor phát hiện cho bạn. Ví dụ trong VS Code, lỗi cú pháp
được đánh dấu bằng đường răng cưa đỏ như hình sau (lỗi thụt đầu
dòng ở dòng code thứ hai:
▪
Lỗi logic (logical errors): dạng lỗi này là code được viết sai thuật
toán, sai logic, dẫn tới kết quả không đúng. Ví dụ khi viết code giải
phương trình bậc 2, bạn ghi sai điều kiện: khi biệt số delta dương
mà lại in ra thông báo phương trình vô nghiệm. Ví dụ khác là khi
code tìm đường đi ngắn nhất, bạn đã ghi sai một lệnh tính toán
quãng đường nào đó, dẫn tới kết quả trả về không phải đường đi
ngắn nhất.
Lỗi này dễ xuất hiện khi bạn viết các chương trình lớn, phức tạp
hoặc code được viết bởi một nhóm và các mô tả hàm không rõ ràng,
dẫn tới các thành viên cài đặt không đúng ý nhau.
Để xử lý dạng lỗi này, chúng ta sử dụng các kỹ thuật gỡ lỗi (debug)
như mô tả trong chương này.
▪
86
▪
Lỗi khi chạy (runtime errors, hay còn được gọi là exceptions):
dạng lỗi này khá thú vị, đôi khi khó phát hiện, vì không phải lúc
nào nó cũng xuất hiện khi bạn chạy một đoạn code. Hình dung bạn
có một đoạn code viết đúng cú pháp, đúng logic, nhưng khi chạy
code, có một vài lần chạy sẽ gặp lỗi, còn những lần chạy khác lại
không bị. Ví dụ đoạn code sau:
N = int(input('Nhap 1 so nguyen duong:'))
N_nghich_dao = 1/N
Đoạn code trên chỉ bị lỗi khi người dùng nhập N = 0 (còn khi người
dùng nhập N khác 0 thì không có lỗi phát sinh). Xem thêm các ví
dụ khác ở phần dưới.
Trong các lỗi trên, lỗi cú pháp dễ xử lý. Bạn chỉ cần học cú pháp
và viết đúng là được. Trường hợp bạn viết sai, IDE và code editor sẽ đánh
dấu cho bạn.
Đối với lỗi logic bạn cần dùng các kỹ thuật debug (xem mục 8.3).
Còn lỗi runtime thì trong Python hỗ trợ cú pháp bắt lỗi try/except (xem
mục kế tiếp).
8.2 Xử lý lỗi runtime
Python cung cấp khối lệnh try/except để hỗ trợ quản lý các lệnh có
nguy cơ gây ra lỗi runtime. Khi sử dụng try/except, nếu có lỗi runtime thì
chương trình của bạn cũng sẽ không bị đổ vỡ và có thể được xử lý gọn
gàng.
Cú pháp của khối lệnh try/except:
try:
#Đặt các dòng lệnh có lỗi runtime ở đây
except ten_exception1:
#Lệnh xử lý exception 1
except ten_exception2:
#Lệnh xử lý exception 2
except:
#Lệnh xử lý các exception khác
Trong cú pháp trên, khối try chứa các lệnh có thể bị lỗi runtime,
các khối except bên dưới chứa các lệnh xử lý các exception. Tùy theo
87
exception xuất hiện mà các lệnh tương ứng sẽ được thực thi để xử lý. Số
lượng các khối except là tùy ý (theo số lỗi runtime có thể xảy ra của các
lệnh ở khối try), ngoại trừ khối except cuối cùng (khối except không đi
kèm tên exception) thì chỉ xuất hiện tối đa một lần trong một khối
try/except. Để hiểu rõ hơn về khối lệnh này chúng ta hãy xem các ví dụ
bên dưới.
Ví dụ 8.1: Cho một list chứa các nhiệt độ được đo hằng ngày (mỗi
phần tử là nhiệt độ của một ngày: phần tử có index 0 là nhiệt độ ngày
0, phần tử có index 1 là nhiệt độ ngày 1…). Đoạn code bên dưới cho
phép người dùng nhập vào 1 ngày (số nguyên dương) và in ra nhiệt
độ của ngày đó.
# Khi không dùng try/except:
# Nếu người dùng nhập ngày lớn hơn 4 sẽ bị lỗi không
có phần tử (index out of range)
temperatures_each_day = [30, 29, 32, 34, 31]
i = int(input('Enter the day:'))
print('Temperature:', temperatures_each_day[i])
# Khi dùng try/except:
# Nếu người dùng nhập ngày lớn hơn 4 sẽ hiện ra thông
báo không tìm thấy dữ liệu và chương trình không bị đổ
vỡ.
temperatures_each_day = [30, 29, 32, 34, 31]
i = int(input('Enter the day:'))
try:
print('Temperature:', temperatures_each_day[i])
except IndexError:
print('Cannot find data for the input day. May try
a smaller value for day.')
Ví dụ 8.2: Đoạn code bên dưới cùng chức năng như ví dụ bên trên nhưng
xử lý nhiều loại lỗi runtime hơn: lỗi index out of range, lỗi nhập liệu sai
kiểu (yêu cầu số nhưng nhập chữ), và lỗi khác.
88
temperatures_each_day = [30, 29, 32, 34, 31]
try:
i = int(input('Enter the day:'))
print('Temperature:', temperatures_each_day[i])
except IndexError:
print('Cannot find data for the input day. May
try a smaller value for day.')
except ValueError: # Lỗi không nhập số
print('Please enter a number for day.')
except: # Lỗi khác
print('An unknown error happened.')
Ví dụ 8.3: Đoạn code sau cho phép người dùng (ví dụ nhân viên thu ngân)
nhập liên tiếp giá sản phẩm cho đến khi người dùng không nhập nữa (để
trống ô input và nhấn enter) thì sẽ dừng và trả tổng giá trị của đơn hàng.
Trong code này, lỗi runtime có thể xuất hiện khi người dùng nhập sai kiểu
dữ liệu (không nhập số). Khi đó chương trình có thể bị crashed và toàn bộ
các giá sản phẩm đã nhập sẽ bị mất. Vì vậy, chúng ra cần dùng khối
try/except để xử lý lỗi nhập liệu này.
# Khi không dùng try/except:
# Hãy thử nhập dữ liệu không phải số.
sum_val = 0
while True:
user_input = input('Enter an item price:')
if user_input == '':
print('Done.')
break
else:
num = float(user_input)
sum_val += num
print('Current total amount:',sum_val)
89
# Khi dùng try/except:
# Nếu bạn nhập dữ liệu không phải số sẽ nhận được thông
báo nhập lại và chương trình vẫn hoạt động tiếp tục.
sum_val = 0
while True:
user_input = input('Enter an item price:')
if user_input == '':
print('Done.')
break
else:
try:
num = float(user_input)
except ValueError:
print('Please input a number.')
continue
sum_val += num
print('Current total amount:',sum_val)
8.3 Xử lý lỗi logic
Lỗi logic không thể được xử lý tự động như kiểu dùng khối
try/except khi xử lý lỗi runtime. Các công cụ hỗ trợ debug của IDE có thể
hỗ trợ bạn dò tìm lỗi dễ dàng hơn là ngồi đọc code thủ công bằng mắt.
Phần bên dưới trình bày cách debug với VS Code.
Đoạn code bên dưới được viết để tính giai thừa của một số nguyên
dương N. Tuy nhiên đoạn code này chứa các lỗi logic. Chúng ta sẽ sử dụng
tính năng Debug Cell của VS Code để dò tìm ra lỗi này.
#%% Tính giai thừa
N = int(input('Nhap so nguyen duong'))
giai_thua = 0
i = 1
while i<=N:
giai_thua *= N
print('N! =', giai_thua)
90
Để kích hoạt tính năng Debug Cell bạn nhấn vào “Debug Cell” nằm ngay
phía trên mỗi cell:
Sau khi nhấn “Debug Cell”, VS Code sẽ chuyển code sang chế độ chạy
từng dòng. Để ý trong hình bên dưới dòng 3 được highlight: đây chính là
dòng lệnh sẽ được chạy tiếp theo. Để chạy lệnh này, bạn nhấn nút Step
Over (F10) như hình dưới:
Khi nhấn Step Over lệnh input sẽ được thực thi và yêu cầu nhập liệu. Giả
sử ta nhập 5 như hình dưới:
Sau khi Enter, VS Code sẽ quay lại cửa sổ lệnh và highlight lệnh tiếp theo:
91
Lúc này ta tiếp tục nhấn Step Over (F10) để chạy dòng lệnh 4. Khi chạy
xong dòng 4 thì dòng 5 sẽ được highlight. Lúc này, nếu bạn rê chuột lên
biến giai_thua sẽ thấy xuất hiện ô ghi giá trị hiện tại của biến (giá trị 0).
Cứ tiếp tục thực hiện nhấn Step Over như trên ta sẽ lần lượt thấy các màn
hình như sau:
92
93
Có thể thấy vòng lặp đang được thực thi. Tuy nhiên, sau khi nhấn Step
Over 6 lần hoặc hơn, bạn vẫn thấy chương trình của chúng ta dừng ở vòng
lặp. Đáng lẽ lệnh lặp này chỉ chạy 5 lần vì chúng ta đang tính N! với N =
5. Như vậy vòng lặp đang bị lặp quá nhiều lần.
Kiểm tra giá trị của biến i (bằng cách rê chuột lên trên biến i) bạn sẽ thấy
giá trị của nó luôn luôn là 1. Như vậy, vòng lặp đã thiếu dòng lệnh thay
đổi giá trị cho i. Đây là một lỗi.
Khi đã phát hiện ra lỗi, bạn dừng trình debug bằng cách nhấn Disconnect
(Shift-F5) như hình sau:
Lúc này trình debug sẽ dừng và bạn có thể chỉnh code. Giả sử chúng ta
chỉnh code thành như sau:
#%% Tính giai thừa
N = int(input('Nhap so nguyen duong'))
giai_thua =
0
i = 1
while i<=N:
giai_thua *= N
i += 1
print('N! =', giai_thua)
Khi thực thi code này thì vòng lặp đã dừng sau 5 lần chạy. Tuy nhiên, giá
trị của giai_thua lại bằng 0. Ta có thể thực hiện Debug Cell như đoạn
trên và kiểm tra giá trị của biến giai_thua trong mỗi lần lặp thì thấy giá
trị của nó không thay đổi (luôn là 0):
94
Lúc này bạn có thể phát giác là biến giai_thua đã được khởi tạo nhầm
bằng 0 nên giá trị của nó khi nhân lên không thay đổi. Khi phát hiện lỗi
này ta nhấn Disconnect (Shift-F5) và chỉnh sửa code như sau:
#%% Tính giai thừa
N = int(input('Nhap so nguyen duong'))
giai_thua = 1
i = 1
while i<=N:
giai_thua *= N
i += 1
print('N! =', giai_thua)
Thực hành: Code trên vẫn còn lỗi làm cho giá trị N! chưa được tính đúng.
Hãy tiếp tục chạy debug để dò tìm và chỉnh sửa lỗi này.
8.4 Các lưu ý khi viết code để hạn chế lỗi
Phần trên đã giới thiệu những cách phát hiện và xử lý lỗi. Tuy
nhiên, tốt nhất vẫn là “phòng bệnh hơn chữa bệnh”. Dưới đây liệt kê một
số kinh nghiệm đơn giản có thể giúp bạn hạn chế các lỗi khi lập trình:
▪
▪
Đối với lỗi cú pháp: học kỹ cú pháp và thực hành viết code nhiều,
tự nhiên bạn sẽ ít mắc và dễ dàng xử lý khi gặp dạng lỗi này.
Đối với lỗi logic: bạn nên thực hiện
1. Chia nhỏ code: trước khi lập trình một bài toán lớn, bạn nên dành
thời gian chia nhỏ các chức năng, thành phần của code và lên kế
95
▪
96
hoạch viết chúng có thứ tự để dễ dàng viết và kiểm thử trong quá
trình viết.
2. Viết code sạch: đừng quên áp dụng các kinh nghiệm viết code
sạch như đặt tên biến, tên hàm dễ hiểu, sử dụng comments để làm
rõ code, viết các hàm nhỏ, mỗi hàm một chức năng.
3. Kiểm thử thường xuyên: đừng đợi đến lúc viết xong hết chương
trình mới chạy thử và kiểm tra kết quả. Đặc biệt đối với những
chương trình lớn, mỗi khi viết xong một đoạn hoặc một hàm, bạn
nên chạy thử chúng để xem kết quả. Nếu có sai sót chúng ta sẽ dễ
dàng điều chỉnh vì mỗi lần chỉ chỉnh 1 đoạn code hoặc 1 hàm.
4. Thực hành nhiều: muốn viết code giỏi hãy luyện tập viết code
càng nhiều càng tốt. Tự bạn sẽ tích lũy được các kinh nghiệm mà
đôi khi đọc cả quyển sách dày cũng không có được.
Đối với lỗi runtime: chúng ta đơn giản chỉ cần dùng try/except.
Tuy nhiên, vấn đề nằm ở chỗ bạn phải có kinh nghiệm để biết dòng
code nào có thể sinh lỗi runtime hoặc phải có bộ test case đầy đủ
để phát hiện các trường hợp này. Như vậy việc luyện tập viết code
nhiều một lần nữa phát huy tác dụng trong việc cải thiện chất lượng
lập trình của bạn.
Bài tập thực hành
1. Đọc hiểu và viết lại đoạn code sau cho “clean” hơn (đổi tên hàm, tên
biến, thêm chú thích...):
def f1(a, b, c, d):
e =
[]
for i in a:
if i%b==0 and c<=i<=d:
e.append(i)
return e
L1 = [2, 1, 4, -4, 6, 10, 5, 8]
f2 = f1(L1, 2, 5, 10)
print(f2)
2. Đọc hiểu và viết lại đoạn code sau cho “clean” hơn (sửa lời nhắn
input, đổi tên biến, thêm chú thích...).
Yêu cầu: Dùng try / except để bắt exeptions (run time errors).
import numpy as np
a = int(input('Nhap a:'))
b = int(input('Nhap b:'))
n = []
i = 0
while i<a:
c = np.random.randint(0,100)
if c%b==0:
n.append(c)
i += 1
print(n)
3. Tìm hiểu hàm isinstance(), viết code minh họa.
4. Đọc hiểu và tìm lỗi trong đoạn code kiểm tra số nguyên tố sau, biết
rằng đoạn code phải trả về:
97
list2 = [True, False, False, True, False, True, True]
# True nằm ở vị trí số nguyên tố
Yêu cầu: Sử dụng break point. Sửa lỗi và viết lại code cho “clean” hơn.
def kt(a):
b = 1
while(b<a/2):
if a%b == 0:
return False
return True
def kt2(a):
b = []
for c in a:
b.append(kt(c))
return b
list1 = [2, 1, 4, 7, 8, 19, 13]
list2 = kt2(list1)
print(list2)
98
Chương 9
VẼ VỚI MATPLOTLIB
Chương này giới thiệu về thư viện matplotlib hỗ trợ các thao tác vẽ
(plotting) trong Python. Bạn có thể sử dụng matplotlib để trực quan hóa
dữ liệu hoặc đơn giản là vẽ các đồ thị hàm số cho mục đích minh họa.
9.1 Cách thức vẽ trên màn hình kỹ thuật số
Màn hình kỹ thuật số (digital screens) hiển thị các hình ảnh kỹ thuật
số (digital images). Về cơ bản, các hình ảnh kỹ thuật số là một mảng 2
chiều của các pixels, với mỗi pixel là một điểm ảnh. Như hình bên dưới1:
ký tự ‘a’ và hình ảnh phóng to của nó cho thấy các pixels.
Do đó, để vẽ hình ảnh kỹ thuật số, hoặc để hiển thị hình ảnh
trên màn hình kỹ thuật số nói chung, chúng ta cần phải chấm liên tiếp các
pixels này.
Trong Python có một thư viện tên matplotlib cho phép chúng ta vẽ
các hình ảnh bằng cách chấm các điểm ảnh lên cửa sổ vẽ. Sau đó,
matplotlib sẽ nối các điểm ảnh này lại tạo thành hình ảnh cuối cùng. Hãy
xem các ví dụ bên dưới.
1
Nguồn: https://pippin.gimp.org/image_processing/chap_dir.html
99
9.2 Vẽ với thư viện matplotlib
Lưu ý: Cũng như các packages khác, trước khi sử dụng matplotlib,
bạn cần cài đặt thư viện này sử dụng lệnh pip (xem mục 4.2). Sau khi cài
đặt xong, bạn cần import các thư viện như sau để vẽ các hình bên dưới:
import matplotlib.pyplot as plt
import numpy as np
Thư viện tên matplotlib cho phép chúng ta vẽ các hình ảnh bằng cách chấm
các điểm ảnh lên cửa sổ vẽ. Sau đó, matplotlib sẽ nối các điểm ảnh này lại.
Ví dụ: để vẽ một đoạn thẳng, chúng ta cần chấm 2 điểm đầu mút của nó
như hình dưới:
Sau đó matplotlib sẽ tự nối 2 điểm này lại tạo thành đoạn thẳng như sau:
100
Đoạn code tối giản để vẽ ra đoạn thẳng ở trên là1:
x = np.array([2, 7])
y = np.array([1, 9])
plt.plot(x,y)
plt.show()
Trong code trên, x, y là 2 mảng chứa tọa độ của các điểm đầu mút, x là
mảng chứa các hoành độ x, còn y là mảng chứa các tung độ y. Với 2 điểm
có tọa độ (2, 1) và (7, 9) thì mảng x, y tương ứng là: [2, 7] và [1, 9]. Lưu ý
rằng thứ tự các điểm quyết định hình ảnh được vẽ ra. Xem ví dụ sau.
Lưu ý rằng đoạn code trên là đoạn code được đơn giản hóa để giúp bạn nắm bắt được ý
chính của việc vẽ hình với matplotlib. Do đó, bạn đừng lo ngại nếu hình ảnh được vẽ ra
bằng đoạn code này không giống hoàn toàn với hình minh họa.
Để vẽ ra hình giống như hình minh họa, bạn thêm đoạn code sau vào dưới lệnh plt.plot():
1
plt.xticks(np.arange(0,11,1))
plt.yticks(np.arange(0,11,1))
plt.gca().set_aspect('equal')
plt.grid()
Các mục sau của chương này sẽ dần dần giải thích đoạn code trên.
101
Ví dụ 9.1: Vẽ 2 đoạn thẳng liên tiếp.
#%% Code 01:
x = np.array([2, 8, 4])
y = np.array([1, 3, 9])
plt.plot(x,y)
plt.show()
#%% Code 02:
x = np.array([2, 4, 8])
y = np.array([1, 9, 3])
plt.plot(x,y)
plt.show()
Khi thực thi các đoạn code trên, ta thu được kết quả của Code 01 là:
102
Còn kết quả của Code 02 là:
Để ý rằng 3 điểm ảnh đầu mút của 2 đoạn thẳng này là như nhau: (2,1),
(8,3), (4,9). Tuy nhiên, do mảng x, y chứa các điểm này với thứ tự khác
nhau nên sinh ra các đoạn thẳng khác nhau.
Thực hành: Hãy vẽ hình tam giác như bên dưới.
Gợi ý: Bạn cần thêm điểm đầu vào cuối mảng x, y (tức là mảng x, y bây
giờ sẽ chứa 4 điểm) để vẽ thêm đoạn thẳng thứ 3.
103
Thực hành: Viết code vẽ hình như sau:
Ví dụ 9.2: Vẽ đồ thị hàm số y = 3x2 + 4x + 9.
x = np.arange(-4, 3, 0.1)
y = 3*x**2 + 4*x + 9
plt.plot(x,y)
plt.show()
Trong đoạn code trên chúng ta sử dụng hàm np.arange() (từ thư viện
numpy) để tạo ra mảng tọa độ x với giá trị trải đều từ -4 đến 3, bước nhảy
0.1 (tức tạo ra được 70 tọa độ x: -4, -3.9, -3.8, -3.7…). Khi đó, lệnh tính
giá trị tọa độ y:
y = 3*x**2 + 4*x + 9
sẽ sinh ra các tọa độ y tương ứng với các tọa độ x sử dụng phương trình
của hàm số y = 3x2 + 4x + 9. Khi thực thi đoạn code ta sẽ thu được kết
quả đồ thị như sau:
104
Để hiểu rõ hơn về cách vẽ đồ thị trên của matplotlib, chúng ta thử điều
chỉnh đoạn code vẽ ở trên thành như sau:
x = np.arange(-4, 3, 2)
y = 3*x**2 + 4*x + 9
plt.plot(x,y)
plt.show()
So với đoạn code trước, đoạn code này chỉ thay đổi ở bước nhảy của hàm
np.arange() dùng tạo tọa độ x từ 0.1 thành 2. Như vậy số tọa độ x được
sinh ra sẽ giảm từ 70 tọa độ xuống còn 4 tọa độ: -4, -2, 0, 2. Vì vậy, khi
tính tọa độ y ta cũng chỉ thu được 4 tọa độ y tương ứng.
Do đó, đồ thị sinh ra chỉ còn là hình nối của 4 điểm ảnh như hình sau:
105
Thực hành: Vẽ đồ thị hàm số y = cos(5x + π).
9.3 Vẽ đồ thị trong tọa độ cực
Mục trên trình bày cách vẽ với matplotlib. Điểm cốt yếu để vẽ là
tạo ra các tọa độ của điểm ảnh cần vẽ trong hệ tọa độ Descartes. Để vẽ
trong hệ tọa độ cực, bạn chỉ cần thêm một bước chuyển đổi tọa độ từ hệ
tọa độ cực thành tọa độ Descartes. Xem ví dụ sau.
106
Ví dụ 9.3: Vẽ hình xoắn ốc y = 0.5θ.
theta = np.arange(0, 4*np.pi ,0.1)
r = 0.5*theta
x = r*np.cos(theta)
y = r*np.sin(theta)
plt.plot(x,y)
plt.show()
Trong đoạn code trên, 2 dòng lệnh:
theta = np.arange(0, 4*np.pi ,0.1)
r = 0.5*theta
tạo ra tọa độ (θ, r) của các điểm ảnh cần vẽ trong tọa độ cực.
Hai dòng lệnh sau
x = r*np.cos(theta)
y = r*np.sin(theta)
chuyển đổi từ tọa độ cực (θ, r) thành tọa độ Descartes (x, y).
Phần còn lại là của code tương đồng với các đoạn code vẽ ở trên. Kết quả
đồ thị thu được như sau:
107
Thực hành: Thay đổi các giá trị bước nhảy và giá trị đầu cuối của hàm
np.arange() tạo tọa độ θ để xem sự thay đổi của đồ thị được vẽ.
Thực hành: Vẽ đồ thị hàm số r = cos(4, θ).
9.4 Tùy chỉnh hình vẽ
Matplotlib cung cấp nhiều tùy chỉnh giúp bạn thể hiện ảnh được vẽ
theo ý muốn, ví dụ thay đổi màu sắc, thay đổi nét vẽ, thu phóng hình. Mục
này sẽ giới thiệu một số tùy chỉnh thường dùng. Các tùy chỉnh khác bạn
có thể tìm thấy trên trang web của matplotlib https://matplotlib.org/.
108
Để điều chỉnh màu của nét vẽ chúng ta dùng thuộc tính color của hàm
plot() như ví dụ sau:
x = np.arange(-4, 3, .1)
y = 3*x**2 + 4*x + 9
plt.plot(x,y, color = 'green')
plt.show()
Lưu ý: Matplotlib cung cấp sẵn một số màu cơ bản bằng các từ
tiếng Anh như red, green, blue, black. Bạn có thể sử dụng màu hex để chỉ
định một màu tùy ý, ví dụ:
x = np.arange(-4, 3, .1)
y = 3*x**2 + 4*x + 9
plt.plot(x,y, color = '#04a900')
plt.show()
109
Để thay đổi độ dày của nét vẽ, ta dùng thuộc tính linewidth:
x = np.arange(-4, 3, .1)
y = 3*x**2 + 4*x + 9
plt.plot(x,y, linewidth=4)
plt.show()
Lưu ý: Bạn có thể kết hợp các tùy chỉnh với nhau để tạo ra nét vẽ
như ý muốn. Ví dụ để chỉnh màu và độ dày nét vẽ ta kết hợp thuộc tính
color và linewidth của hàm plot():
110
x = np.arange(-4, 3, .1)
y = 3*x**2 + 4*x + 9
plt.plot(x,y, color = '#04a900', linewidth=4)
plt.show()
Để điều chỉnh giới hạn của tọa độ vẽ, ta dùng phương thức axis() với cú
pháp:
plt.axis([xmin, xmax, ymin, ymax])
Ví dụ:
x = np.arange(-4, 3, .1)
y = 3*x**2 + 4*x + 9
plt.plot(x,y)
plt.axis([-6, 4, 0, 50])
plt.show()
Để điều chỉnh cho tỉ lệ của trục tung và hoành bằng nhau, ta dùng lệnh:
plt.axis('equal')
Ví dụ 9.4: Vẽ hình tròn khi không dùng axis('equal').
111
theta = np.arange(0, 2*np.pi ,0.01)
r = 5
x = r*np.cos(theta)
y = r*np.sin(theta)
plt.plot(x,y)
plt.show()
Khi thực thi đoạn code trên sẽ thu được kết quả như hình dưới:
Trong hình trên, do các trục tọa độ có tỷ lệ không đồng nhất nên hình tròn
được vẽ ra trông giống như hình ellipse. Khi dùng axis('equal') sẽ cho kết
quả tròn đều như hình bên dưới.
theta = np.arange(0, 2*np.pi ,0.01)
r = 5
x = r*np.cos(theta)
y = r*np.sin(theta)
plt.axis('equal')
plt.plot(x,y)
plt.show()
112
Để thêm lưới tọa độ, ta dùng:
plt.grid(True)
Ví dụ 9.5:
theta = np.arange(0, 2*np.pi ,0.01)
r = 5
x = r*np.cos(theta)
y = r*np.sin(theta)
plt.axis('equal')
plt.plot(x,y)
plt.grid(True)
plt.show()
113
Trong trường hợp vẽ nhiều hình trên cùng một cửa sổ vẽ (figure), bạn có
thể dùng phương thức legend() để thêm chú thích. Xem ví dụ bên dưới.
Ví dụ 9.6: Vẽ 2 vòng tròn với bán kính khác nhau.
theta = np.arange(0, 2*np.pi ,0.01)
r = 4
x = r*np.cos(theta)
y = r*np.sin(theta)
plt.plot(x,y)
r = 5
x = r*np.cos(theta)
y = r*np.sin(theta)
plt.plot(x,y)
plt.legend(['r1 = 4','r2 = 5'])
plt.axis('equal')
plt.grid(True)
plt.show()
114
Để thêm chú thích cho trục x, trục y và tên cho hình vẽ, ta dùng lần lượt
các phương thức sau:
plt.xlabel()
plt.ylabel()
plt.title()
theta = np.arange(0, 2*np.pi ,0.01)
r = 4
x = r*np.cos(theta)
y = r*np.sin(theta)
plt.plot(x,y)
r = 5
x = r*np.cos(theta)
y = r*np.sin(theta)
plt.plot(x,y)
plt.xlabel('Trục x')
115
plt.ylabel('Trục y')
plt.title('Hình tròn đồng tâm')
plt.legend(['r1 = 4','r2 = 5'])
plt.axis('equal')
plt.grid(True)
plt.show()
9.5 Vẽ trên nhiều phân vùng với subplotlib
Để tách một cửa sổ vẽ (figure) thành nhiều phân vùng, ta có thể
dùng hàm subplotlib với cú pháp như sau:
subplot(so_hang, so_cot, vi_tri)
Trong đó so_hang và so_cot là số lượng hàng và cột cần chia tách,
còn vị trí là số thứ tự của ô cần vẽ. Xem các ví dụ sau.
116
vi_tri = 1
vi_tri = 2
vi_tri = 3
vi_tri = 4
Để chia cửa sổ vẽ thành 4 ô như hình trên (2 hàng, 2 cột) và vẽ vào
ô ở vị trí thứ nhất (ô có gạch chéo), ta dùng lệnh: subplot(2,2,1)
Để chia cửa sổ vẽ thành 4 ô như hình dưới (2 hàng, 3 cột) và vẽ
vào ô ở vị trí thứ 5 (ô có gạch chéo), ta dùng lệnh: subplot(2,3,5)
vi_tri = 1
vi_tri = 2
vi_tri = 3
vi_tri = 4
vi_tri = 5
vi_tri = 6
Để chia cửa sổ vẽ thành 4 ô như hình dưới (2 hàng, 3 cột) và vẽ vào ô
ở vị trí thứ 5 (ô có gạch chéo), ta dùng lệnh: subplot(2,3,(3, 6))
vi_tri = 1
vi_tri = 2
vi_tri =
(3, 6)
vi_tri = 4
vi_tri = 5
117
Ví dụ 9.8: Đoạn code sau vẽ 3 đồ thị của các hàm số trên các phân vùng
khác nhau. Để ý cách dùng hàm subplot(): phải được đặt trước khi gọi hàm
plot(). Ngoài ra lưu ý chỉ để lệnh show() sau khi plot hình cuối cùng.
# Plot a rose
plt.subplot(2,2,1)
a= 4
n= 4
theta = np.arange(0,4*np.pi,0.01)
r = a * np.cos(n*theta)
x = r*np.cos(theta)
y = r*np.sin(theta)
plt.plot(x,y)
# Plot a spiral
plt.subplot(2,2,2)
a = 2
theta = np.arange(0, 4*np.pi, 0.1)
r = a*theta
x = r*np.cos(theta)
y = r*np.sin(theta)
plt.plot(x,y)
# Plot a parabola
plt.subplot(2,2,(3,4))
x = np.arange(-6, 5, 0.2)
y = 5*x**2 + 4*x - 1
plt.plot(x,y)
plt.show()
Kết quả khi chạy đoạn code trên:
118
119
Bài tập thực hành
1. Vẽ đồ thị hàm bậc 5:
𝑦 = 3𝑥 5 + 20𝑥 4 – 10𝑥 3 – 240𝑥 2 – 250𝑥 + 200
Yêu cầu: giống như hình về màu, style, đầy đủ xlabel, ylabel,
title, và axis có khoảng giá trị như hình.
2. Vẽ các đồ thị hàm số sau, với phương trình được cho trong legend.
Yêu cầu: đơn vị trên trục Ox, Oy bằng nhau, giống như hình sau
về màu, style, có đầy đủ legend, grid.
120
3. Tìm hiểu hàm plt.bar() và viết code minh họa vẽ một biểu đồ cột
tùy ý.
4. Tìm hiểu hàm plt.hist() và viết code minh họa vẽ một histogram
của một dữ liệu tùy ý.
5. Tìm hiểu vẽ 3D và vẽ hyperboloid có phương trình
−0.3𝑥 2 − 0.3𝑦 2 + 𝑧 2 = 1.
Lưu ý:
+ Biến đổi phương trình của hàm số để có giá trị của z theo x, y.
+ Dùng colormap ‘jet’.
+ Trong các hàm ax.plot_surface(): ghi thêm tham số vmin=-5,
vmax=5 để có dãy màu như hình.
121
PHỤ LỤC
Mã nguồn bài tập có lời giải chương 2
Bài 1: Viết chương trình kiểm tra ký tự người dùng nhập là nguyên
âm hay phụ âm. Lưu ý chương trình này chỉ được sử dụng để nhận
đầu vào là các ký tự thường không viết hoa. Để xử lý các ký tự viết
hoa hãy thêm vào các giá trị so sánh đối với chữ viết hoa.
# Read a letter from the user
letter = input("Enter a letter: ")
# Classify the letter and report the result
if letter == "a" or letter == "e" or \
letter == "i" or letter == "o" or \
letter == "u":
print("It’s a vowel.")
elif letter == "y":
print("Sometimes it’s a vowel... Sometimes it’s a
consonant.")
else:
print("It’s a consonant.")
Bài 2: Viết chương trình xác định số ngày của một tháng cho trước
# Display the number of days in a month.
# Read the month name from the user
month = input("Enter the name of a month: ")
# Compute the number of days in the month
days = 31
if month == "April" or month == "June" or \
month == "September" or month == "November":
days = 30
122
elif month == "February":
days = "28 or 29"
# Display the result
print(month, "has", days, "days in it.")
Bài 3: Viết chương trình chuyển đổi điểm chữ thành điểm số. Lưu ý
hàm letter = letter.upper() dùng để chuyển đổi bất kỳ ký tự
thường nào được nhập từ người dùng trở thành ký tự hoa và lưu lại
vào cùng biến.
# Convert from a letter grade to a number of grade
points.
A = 4.0
A_MINUS = 3.7
B_PLUS = 3.3
B = 3.0
B_MINUS = 2.7
C_PLUS = 2.3
C = 2.0
C_MINUS = 1.7
D_PLUS = 1.3
D = 1.0
F = 0
INVALID = -1
# Read the letter grade from the user
letter = input("Enter a letter grade: ")
letter = letter.upper()
# Convert from a letter grade to a number of grade
points using -1 grade points as a sentinel
123
# value indicating invalid input
if letter == "A+" or letter == "A":
gp = A
elif letter == "A-":
gp = A_MINUS
elif letter == "B+":
gp = B_PLUS
elif letter == "B":
gp = B
elif letter == "B-":
gp = B_MINUS
elif letter == "C+":
gp = C_PLUS
elif letter == "C":
gp = C
elif letter == "C-":
gp = C_MINUS
elif letter == "D+":
gp = D_PLUS
elif letter == "D":
gp = D
elif letter == "F":
gp = F
else:
gp = INVALID
# Report the result
if gp == INVALID:
print("That wasn’t a valid letter grade.")
else:
124
print("A(n)", letter, "is equal to", gp, "grade
points.")
Bài 4: Viết chương trình đánh giá hiệu quả làm việc của nhân viên
# Report whether an employee’s performance is
unacceptable, acceptable or meritorious based on the
rating entered by the user.
RAISE_FACTOR = 2400.00
UNACCEPTABLE = 0
ACCEPTABLE = 0.4
MERITORIOUS = 0.6
# Read the rating from the user
rating = float(input("Enter the rating: "))
# Classify the performance
if rating == UNACCEPTABLE:
performance = "Unacceptable"
elif rating == ACCEPTABLE:
performance = "Acceptable"
elif rating >= MERITORIOUS:
performance = "Meritorious"
else:
performance = ""
# Report the result
if performance == "":
print("That wasn’t a valid rating.")
else:
print("Based on that rating, your performance is
%s." % performance)
125
print("You will receive a raise of $%.2f." %
(rating * RAISE_FACTOR))
Bài 5: Viết chương trình xác định năm nhuận
# Read the year from the user
year = int(input("Enter a year: "))
# Determine if it is a leap year
if year % 400 == 0:
isLeapYear = True
elif year % 100 == 0:
isLeapYear = False
elif year % 4 == 0:
isLeapYear = True
else:
isLeapYear = False
# Display the result
if isLeapYear:
print(year, "is a leap year.")
else:
print(year, "is not a leap year.")
126
Mã nguồn bài tập có lời giải chương 3
Bài 1: Viết chương trình tính chu vi của một đa giác
# Compute the perimeter of a polygon constructed from
points entered by the user. A blank line will be
entered for the x-coordinate to indicate that all of
the points have been entered.
from math import sqrt
# Store the perimeter of the polygon
perimeter = 0
# Read the coordinate of the first point
first_x = float(input("Enter the first x-coordinate:
"))
first_y = float(input("Enter the first y-coordinate:
"))
# Provide initial values for prev x and prev y
prev_x = first_x
prev_y = first_y
# Read the remaining coordinates
line = input("Enter the next x-coordinate (blank to
quit): ")
while line != "":
# Convert the x-coordinate to a number and read
the y coordinate
x = float(line)
y = float(input("Enter the next y-coordinate: "))
# Compute the distance to the previous point and
add it to the perimeter
127
dist = sqrt((prev_x - x) ** 2 + (prev_y - y) **
2)
perimeter = perimeter + dist
# Set up prev x and prev y for the next loop
iteration
prev_x = x
prev_y = y
# Read the next x-coordinate
line = input("Enter the next x-coordinate (blank
to quit): ")
# Compute the distance from the last point to the
first point and add it to the perimeter
dist = sqrt((first_x - x) ** 2 + (first_y - y) ** 2)
perimeter = perimeter + dist
# Display the result
print("The perimeter of that polygon is", perimeter)
Bài 2: Viết chương trình tính bit parity của một nhóm 8 bit nhị phân
được nhập bởi người dùng sử dụng parity chẵn.
# Compute the parity bit using even parity for sets
of 8 bits entered by the user.
# Read the first line of input
line = input("Enter 8 bits: ")
# Continue looping until a blank line is entered
while line != "":
# Ensure that the line has a total of 8 zeros and
ones and exactly 8 characters
128
if line.count("0") + line.count("1") != 8 or
len(line) != 8:
# Display an appropriate error message
print("That wasn’t 8 bits... Try again.")
else:
# Count the number of ones
ones = line.count("1")
# Display the parity bit
if ones % 2 == 0:
print("The parity bit should be 0.")
else:
print("The parity bit should be 1.")
# Read the next line of input
line = input("Enter 8 bits: ")
Bài 3: Viết chương trình chuyển đổi số từ hệ thập phân sang nhị phân.
# Convert a number from decimal (base 10) to binary
(base 2).
NEW_BASE = 2
# Read the number to convert from the user
num = int(input("Enter a non-negative integer: "))
# Generate the binary representation of num, storing
it in result
result = ""
q = num
# Perform the body of the loop once
129
r = q % NEW_BASE
result = str(r) + result
q = q // NEW_BASE
# Keep on looping until q is 0
while q > 0:
r = q % NEW_BASE
result = str(r) + result
q = q // NEW_BASE
# Display the result
print(num, "in decimal is", result, "in binary.")
130
Mã nguồn bài tập có lời giải chương 5
Bài 1: Chương trình sẽ đọc một chuỗi từ người dùng sau đó sẽ dịch
chuỗi gồm các ký tự và số thành mã Morse.
# Python program to implement Morse Code Translator
'''
VARIABLE KEY
'cipher' -> 'stores the morse translated form of the
english string'
'decipher' -> 'stores the english translated form of
the morse string'
'citext' -> 'stores morse code of a single character'
'i' -> 'keeps count of the spaces between morse
characters'
'message' -> 'stores the string to be encoded or
decoded'
'''
# Dictionary representing the morse code chart
MORSE_CODE_DICT = { 'A':'.-', 'B':'-...',
'C':'-.-.', 'D':'-..', 'E':'.',
'F':'..-.', 'G':'--.', 'H':'....',
'I':'..', 'J':'.---', 'K':'-.-',
'L':'.-..', 'M':'--', 'N':'-.',
'O':'---', 'P':'.--.', 'Q':'--.-',
'R':'.-.', 'S':'...', 'T':'-',
'U':'..-', 'V':'...-', 'W':'.--',
'X':'-..-', 'Y':'-.--', 'Z':'--..',
'1':'.----', '2':'..---', '3':'...--',
'4':'....-', '5':'.....', '6':'-....',
'7':'--...', '8':'---..', '9':'----.',
131
'0':'-----', ', ':'--..--', '.':'.-.-.-',
'?':'..--..', '/':'-..-.', '-':'-....-',
'(':'-.--.', ')':'-.--.-'}
# Function to encrypt the string
# according to the morse code chart
def encrypt(message):
cipher = ''
for letter in message:
if letter != ' ':
# Looks up the dictionary and adds the
# corresponding morse code
# along with a space to separate
# morse codes for different characters
cipher += MORSE_CODE_DICT[letter] + ' '
else:
# 1 space indicates different characters
# and 2 indicates different words
cipher += ' '
return cipher
# Function to decrypt the string
# from morse to english
def decrypt(message):
# extra space added at the end to access the
# last morse code
message += ' '
132
decipher = ''
citext = ''
for letter in message:
# checks for space
if (letter != ' '):
# counter to keep track of space
i = 0
# storing morse code of a single character
citext += letter
# in case of space
else:
# if i = 1 that indicates a new character
i += 1
# if i = 2 that indicates a new word
if i == 2 :
# adding space to separate words
decipher += ' '
else:
# accessing the keys using their
values (reverse of encryption)
decipher +=
list(MORSE_CODE_DICT.keys())[list(MORSE_CODE_DICT
.values()).index(citext)]
133
citext = ''
return decipher
# Hard-coded driver function to run the program
def main():
message = "GEEKS-FOR-GEEKS"
result = encrypt(message.upper())
print (result)
message = "--. . . -.- ... -....- ..-. --- .-. ....- --. . . -.- ... "
result = decrypt(message)
print (result)
# Executes the main function
if __name__ == '__main__':
main()
134
Mã nguồn bài tập có lời giải chương 7
Bài 1: Viết chương trình tính giá taxi
#The start point of the program
def main():
#Get the information of the distance traveled by
the customer
distanceTraveled=int(input("The distance traveled
by the customer (in KM): "))
#calculate the taxi fare
taxiFare=calculateTaxiFare(distanceTraveled)
#display it to the passenger for the payment to
be received.
print(f"The taxi fare is: ${taxiFare}")
#This function allows to calculate the taxi fare
def calculateTaxiFare(distanceTraveled):
#The taxi fare consists of a base fare of RM 4.00
#plus charges of RM 0.25 for every 140 meters
traveled.
return 4.00+(((distanceTraveled*1000)//140)*0.25)
main()
Bài 2: Tính trung vị của 3 điểm
## Compute
statements
the
median
of
three
values
using
if
# @param a the first value
# @param b the second value
# @param c the third value
# @return the median of values a, b and c
135
def median(a, b, c):
if a < b and b < c or a > b and b > c:
return b
if b < a and a < c or b > a and a > c:
return a
if c < a and b < c or c > a and b > c:
return c
## Compute the median of three values using the min
and max functions and a little bit of
# arithmetic
# @param a the first value
# @param b the second value
# @param c the third value
# @return the median of values a, b and c
def alternateMedian(a, b, c):
return a + b + c - min(a, b, c) - max(a, b, c)
# Display the median of 3 values entered by the user
def main():
x = float(input("Enter the first value: "))
y = float(input("Enter the second value: "))
z = float(input("Enter the third value: "))
print("The median value is:", median(x, y, z))
print("Using the alternative method, it is:", \
alternateMedian(x, y, z))
# Call the main function
main()
136
Bài 3: Chương trình xác định số nguyên tố.
## Determine whether or not a number is prime
# @param n the integer to test
# @return True if the number is prime, False
otherwise
def isPrime(n):
if n <= 1:
return False
# Check each number from 2 up to but not
including n to see if it divides evenly into n
for i in range(2, n):
if n % i == 0:
return False
return True
# Determine if a number entered by the user is prime
def main():
value = int(input("Enter an integer: "))
if isPrime(value):
print(value, "is prime.")
else:
print(value, "is not prime.")
# Call the main function if the file has not been
imported
if __name__ == "__main__":
main()
Bài 4: Xác định số nguyên tố liền kề sau số n
def next_prime(n: int) -> int:
if n < 0:
137
raise ValueError('Negative numbers can not be
primes')
# Base case
if n <= 1:
return 2
# For i as every odd number between n + 1 and n + 200
for i in range(n + 1 + (n % 2), n + 200, 2):
# For every odd number from 3 to i (3 because
we covered base case)
for j in range(3, i, 2):
# If remained is equals to 0
if not i % j:
# break current loop
break
# If loop j didn't break [nobreak: ]
else:
return i
raise RuntimeError('Failed to compute next prime
number :c')
def main():
while True:
try:
num = int(input('Enter positive number:
'))
print(f'Next prime is:
{next_prime(num)}')
break
except ValueError:
print('Please enter a positive integer!')
if __name__ == '__main__':
main()
138
Bài 5: Chương trình kiểm tra tính bảo mật của mật khẩu
# Check whether or not a password is good. A good
password is at least 8 characters and
# contains an uppercase letter, a lowercase letter
and a number.
# @param password the password to check
# @return True if the password is good, False
otherwise
def checkPassword(password):
has_upper = False
has_lower = False
has_num = False
# Check each character in the password and see
which requirement it meets
for ch in password:
if ch >= "A" and ch <= "Z":
has_upper = True
elif ch >= "a" and ch <= "z":
has_lower = True
elif ch >= "0" and ch <= "9":
has_num = True
# If the password has all 4 properties
if len(password) >= 8 and has_upper and has_lower
and has_num:
return True
# The password is missing at least one property
return False
# Demonstrate the password checking function
139
def main():
p = input("Enter a password: ")
if checkPassword(p):
print("That’s a good password.")
else:
print("That isn’t a good password.")
# Call the main function only if the file has not
been imported into another program
if __name__ == "__main__":
main()
Bài 6: Chương trình chuyển đổi giá trị giữa các hệ thống số
# Convert a number from one base to another. Both the
source base and the destination base must be between
2 and 16.
from hex_digit import *
## Convert a number from base 10 to base new base
# @param num the base 10 number to convert
# @param new base the base to convert to
# @return the string of digits in new base
def dec2n(num, new_base):
# Generate the representation of num in base new
base, storing it in result
result = ""
q = num
# Perform the body of the loop once
r = q % new_base
result = int2hex(r) + result
q = q // new_base
140
# Continue looping until q is 0
while q > 0:
r = q % new_base
result = int2hex(r) + result
q = q // new_base
# Return the result
return result
## Convert a number from base b to base 10
# @param num the base b number, stored in a string
# @param b the base of the number to convert
# @return the base 10 number
def n2dec(num, b):
decimal = 0
# Process each digit in the base b number
for i in range(len(num)):
decimal = decimal * b
decimal = decimal + hex2int(num[i])
# Return the result
return decimal
# Convert a number between two arbitrary bases
def main():
# Read the base and number from the user
from_base = int(input("Base to convert from (216): "))
if from_base < 2 or from_base > 16:
print("Only bases between 2 and 16 are
supported.")
print("Quitting...")
quit()
141
from_num = input("Sequence of digits in that
base: ")
# Convert to base 10 and display the result
dec = n2dec(from_num, from_base)
print("That’s %d in base 10." % dec)
# Convert to the new base and display the result
to_base = int(input("Enter the base to convert to
(2-16): "))
if to_base < 2 or to_base > 16:
print("Only bases between 2 and 16 are
supported.")
print("Quitting...")
quit()
to_num = dec2n(dec, to_base)
print("That's %s in base %d." % (to_num,
to_base))
# Call the main function
main()
142
Keywords của Python1
1
Keyword
Mô tả
and
Phép và
as
Tạo tên thay thế
assert
Dành cho debug
break
Dừng vòng lặp
class
Định nghĩa lớp
continue
Chạy vòng lặp tiếp theo
def
Định nghĩa hàm
del
Xóa một đối tượng
elif
Dùng trong khối lệnh if
else
Dùng trong khối lệnh if
except
Dùng trong khối lệnh try/except
False
Giá trị false
finally
Dùng trong khối lệnh try/except
for
Vòng lặp for
from
Dùng trong lệnh import
global
Khai báo biến global
if
Dùng trong khối lệnh if
Nguồn: https://www.w3schools.com/python/python_ref_keywords.asp
143
144
import
Lệnh import
in
Kiểm tra xem phần tử có nằm trong mảng không
is
Kiểm tra xem 2 biến có bằng nhau không
lambda
Tạo hàm lambda
None
Giá trị null
nonlocal
Khai báo biến non-local
not
Phép toán logic
or
Phép toán logic
pass
Lệnh null (không thực thi gì cả)
raise
Tạo một exception
return
Trả về giá trị trong hàm
True
Giá trị true
try
Dùng trong lệnh try/except
while
Tạo vòng lặp while
with
Khối try/except đơn giản
yield
Tạo ra giá trị cho hàm
Cài đặt các thuật toán sắp xếp bằng Python
Nguồn: https://realpython.com/sorting-algorithms-python/
# THUẬT TOÁN SẮP XẾP NỔI BỌT (BUBBLE SORT):
def bubble_sort(array):
n = len(array)
for i in range(n):
# Create a flag that will allow the function
to terminate early if there's nothing left to sort
already_sorted = True
# Start looking at each item of the list one
by one, comparing it with its adjacent value. With
each iteration, the portion of the array that you
look at shrinks because the remaining items have
already been sorted.
for j in range(n - i - 1):
if array[j] > array[j + 1]:
# If the item you're looking at is
greater than its adjacent value, then swap them
array[j], array[j+1] = array[j + 1],
array[j]
# Since you had to swap two elements,
set the `already_sorted` flag to `False` so the
algorithm doesn't finish prematurely
already_sorted = False
# If there were no swaps during the last
iteration, the array is already sorted, and you can
terminate
145
if already_sorted:
break
return array
# THUẬT TOÁN SẮP XẾP CHÈN (INSERTION SORT):
def insertion_sort(array):
# Loop from the second element of the array until
the last element
for i in range(1, len(array)):
# This is the element we want to position in
its correct place
key_item = array[i]
# Initialize the variable that will be used
to find the correct position of the element
referenced by `key_item`
j = i - 1
# Run through the list of items (the left
portion of the array) and find the correct position
of the element referenced by `key_item`. Do this only
if `key_item` is smaller than its adjacent values.
while j >= 0 and array[j] > key_item:
# Shift the value one position to the
left and reposition j to point to the next element
(from right to left)
array[j + 1] = array[j]
j -= 1
# When you finish shifting the elements, you
can position `key_item` in its correct location
146
array[j + 1] = key_item
return array
# THUẬT TOÁN SẮP XẾP TRỘN (MERGE SORT):
def merge(left, right):
# If the first array is empty, then nothing needs
to be merged, and you can return the second array as
the result
if len(left) == 0:
return right
# If the second array is empty, then nothing
needs to be merged, and you can return the first
array as the result
if len(right) == 0:
return left
result = []
index_left = index_right = 0
# Now go through both arrays until all the
elements make it into the resultant array
while len(result) < len(left) + len(right):
# The elements need to be sorted to add them
to the resultant array, so you need to decide whether
to get the next element from the first or the second
array
if left[index_left] <= right[index_right]:
result.append(left[index_left])
index_left += 1
else:
result.append(right[index_right])
index_right += 1
147
# If you reach the end of either array, then
you can add the remaining elements from the other
array to the result and break the loop
if index_right == len(right):
result += left[index_left:]
break
if index_left == len(left):
result += right[index_right:]
break
return result
# THUẬT TOÁN SẮP XẾP NHANH (QUICK SORT):
from random import randint
def quicksort(array):
# If the input array contains fewer than two
elements, then return it as the result of the
function
if len(array) < 2:
return array
low, same, high = [], [], []
# Select your `pivot` element randomly
pivot = array[randint(0, len(array) - 1)]
for item in array:
# Elements that are smaller than the `pivot`
go to the `low` list. Elements that are larger than
`pivot` go to the `high` list. Elements that are
equal to `pivot` go to the `same` list.
148
if item < pivot:
low.append(item)
elif item == pivot:
same.append(item)
elif item > pivot:
high.append(item)
# The final result combines the sorted `low` list
with the `same` list and the sorted `high` list
return quicksort(low) + same + quicksort(high)
# THUẬT TOÁN TIMSORT:
def timsort(array):
min_run = 32
n = len(array)
# Start by slicing and sorting small portions of
the input array. The size of these slices is defined
by your `min_run` size.
for i in range(0, n, min_run):
insertion_sort(array, i, min((i + min_run 1), n - 1))
# Now you can start merging the sorted slices.
Start from `min_run`, doubling the size on each
iteration until you surpass the length of the array.
size = min_run
while size < n:
# Determine the arrays that will be merged
together
for start in range(0, n, size * 2):
149
# Compute the `midpoint` (where the first
array ends and the second starts) and the `endpoint`
(where the second array ends)
midpoint = start + size - 1
end = min((start + size * 2 - 1), (n-1))
# Merge the two subarrays.
# The `left` array should go from `start`
to `midpoint + 1`, while the `right` array should go
from `midpoint + 1` to `end + 1`.
merged_array = merge(
left=array[start:midpoint + 1],
right=array[midpoint + 1:end + 1])
# Finally, put the merged array back into
your array
array[start:start+len(merged_array)] =
merged_array
# Each iteration should double the size of
your arrays
size *= 2
return array
150
Cài đặt các thuật toán tìm kiếm trên mảng bằng
Python
Nguồn: https://www.geeksforgeeks.org/searching-algorithms/#algo
# THUẬT TOÁN TÌM KIẾM TUYẾN TÍNH (LINEAR SEARCH)
# If x is present then return its location, otherwise
return -1
def search(arr, n, x):
for i in range(0, n):
if (arr[i] == x):
return i
return -1
# Driver Code
arr = [2, 3, 4, 10, 40]
x = 10
n = len(arr)
# Function call
result = search(arr, n, x)
if(result == -1):
print("Element is not present in array")
else:
print("Element is present at index", result)
# THUẬT TOÁN TÌM KIẾM NHỊ PHÂN (BINARY SEARCH)
# Returns index of x in arr if present, else -1
def binarySearch(arr, l, r, x):
# Check base case
if r >= l:
151
mid = l + (r - l) // 2
# If element is present at the middle itself
if arr[mid] == x:
return mid
# If element is smaller than mid, then it
can only be present in left subarray
elif arr[mid] > x:
return binarySearch(arr, l, mid-1, x)
# Else the element can only be present in
right subarray
else:
return binarySearch(arr, mid+1, r, x)
else:
# Element is not present in the array
return -1
# Driver Code
arr = [2, 3, 4, 10, 40]
x = 10
# Function call
result = binarySearch(arr, 0, len(arr)-1, x)
if result != -1:
print("Element is present at index % d" % result)
else:
print("Element is not present in array")
# THUẬT TOÁN TÌM KIẾM NHẢY (JUMP SEARCH)
# This code is contributed by "Sharad_Bhardwaj".
import math
def jumpSearch( arr , x , n ):
# Finding block size to be jumped
step = math.sqrt(n)
152
# Finding the block where element is present (if
it is present)
prev = 0
while arr[int(min(step, n)-1)] < x:
prev = step
step += math.sqrt(n)
if prev >= n:
return -1
# Doing a linear search for x in block beginning
with prev.
while arr[int(prev)] < x:
prev += 1
# If we reached next block or end
element is not present.
of array,
if prev == min(step, n):
return -1
# If element is found
if arr[int(prev)] == x:
return prev
return -1
# Driver code to test function
arr = [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,
233, 377, 610 ]
x = 55
n = len(arr)
153
# Find the index of 'x' using Jump Search
index = jumpSearch(arr, x, n)
# Print the index where 'x' is located
print("Number" , x, "is at index" ,"%.0f"%index)
# THUẬT TOÁN TÌM KIẾM NỘI SUY (INTERPOLATION SEARCH)
# This code is contributed by Hardik Jain
# If x is present in arr[0..n-1], then returns index
of it, else returns -1.
def interpolationSearch(arr, lo, hi, x):
# Since array is sorted, an element present in
array must be in range defined by corner
if (lo <= hi and x >= arr[lo] and x <= arr[hi]):
# Probing the position with keeping
distribution in mind.
uniform
pos = lo + ((hi - lo) // (arr[hi] - arr[lo]) *
(x - arr[lo]))
# Condition of target found
if arr[pos] == x:
return pos
# If x is larger, x is in right subarray
if arr[pos] < x:
return interpolationSearch(arr, pos + 1, hi, x)
# If x is smaller, x is in left subarray
154
if arr[pos] > x:
return interpolationSearch(arr, lo, pos - 1, x)
return -1
# Driver code
# Array of items in which search will be conducted
arr = [10, 12, 13, 16, 18, 19, 20,
21, 22, 23, 24, 33, 35, 42, 47]
n = len(arr)
# Element to be searched
x = 18
index = interpolationSearch(arr, 0, n - 1, x)
if index != -1:
print("Element found at index", index)
else:
print("Element not found")
# THUẬT TOÁN TÌM KIẾM HÀM MŨ (EXPONENTIAL SEARCH):
# This code is contributed by Harshit Agrawal
# A recursive binary search function returns
location of x in given array arr[l..r] is present,
otherwise -1
def binarySearch( arr, l, r, x):
if r >= l:
mid = l + ( r-l ) // 2
155
# If the element is present at the middle
itself
if arr[mid] == x:
return mid
# If the element is smaller than mid,
it can only be present in the left subarray
then
if arr[mid] > x:
return binarySearch(arr, l,
mid - 1, x)
# Else he element can only be present in the
right
return binarySearch(arr, mid + 1, r, x)
# We reach here if the element is not present
return -1
# Returns the position of first occurrence of x in
array
def exponentialSearch(arr, n, x):
# IF x is present at first location itself
if arr[0] == x:
return 0
# Find range for binary search j by repeated
doubling
i = 1
while i < n and arr[i] <= x:
i = i * 2
156
# Call binary search for the found range
return binarySearch( arr, i // 2,
min(i, n-1), x)
# Driver Code
arr = [2, 3, 4, 10, 40]
n = len(arr)
x = 10
result = exponentialSearch(arr, n, x)
if result == -1:
print ("Element not found in the array")
else:
print ("Element is present at index %d"
%(result))
157
Cài đặt các thuật toán tìm kiếm trên chuỗi bằng
Python
# THUẬT TOÁN NAIVE PATTERN SEARCHING
# Nguồn: https://www.geeksforgeeks.org/naivealgorithm-for-pattern-searching/
# This code is contributed by PrinciRaj1992
def search(pat, txt):
M = len(pat)
N = len(txt)
# A loop to slide pat[] one by one */
for i in range(N - M + 1):
j = 0
# For current index i, check
# for pattern match */
while(j < M):
if (txt[i + j] != pat[j]):
break
j += 1
if (j == M):
print("Pattern found at index ", i)
# Driver's Code
if __name__ == '__main__':
txt = "AABAACAADAABAAABAA"
pat = "AABA"
# Function call
158
search(pat, txt)
# THUẬT TOÁN KMP
# Nguồn: https://www.geeksforgeeks.org/kmp-algorithmfor-pattern-searching/
# This code is contributed by Bhavya Jain
def KMPSearch(pat, txt):
M = len(pat)
N = len(txt)
# create lps[] that will hold the longest prefix
suffix
# values for pattern
lps = [0]*M
j = 0 # index for pat[]
# Preprocess the pattern (calculate lps[] array)
computeLPSArray(pat, M, lps)
i = 0 # index for txt[]
while (N - i) >= (M - j):
if pat[j] == txt[i]:
i += 1
j += 1
if j == M:
print ("Found pattern at index " + str(i-j))
j = lps[j-1]
159
# mismatch after j matches
elif i < N and pat[j] != txt[i]:
# Do not match lps[0..lps[j-1]] characters,
# they will match anyway
if j != 0:
j = lps[j-1]
else:
i += 1
def computeLPSArray(pat, M, lps):
len = 0 # length of the previous longest prefix
suffix
lps[0] # lps[0] is always 0
i = 1
# the loop calculates lps[i] for i = 1 to M-1
while i < M:
if pat[i]== pat[len]:
len += 1
lps[i] = len
i += 1
else:
# This is tricky. Consider the example.
# AAACAAAA and i = 7. The idea is similar
# to search step.
if len != 0:
len = lps[len-1]
160
# Also, note that we do not increment i here
else:
lps[i] = 0
i += 1
txt = "ABABDABACDABABCABAB"
pat = "ABABCABAB"
KMPSearch(pat, txt)
161
INDEX
Biến, 16
break, 58
cell, 12
chuỗi, 81
cửa sổ interactive, 13
đạo văn, 11
debug, 105
dictionary, 72
function, 89
hàm, 88
index, 44
index âm, 44
index không âm, 44
Lệnh if, 22
list, 44
lỗi, 105
mảng, 43
Numpy, 62
numpy array, 62
package, 61
Python, 1
set, 69
slicing, 45
string, 81
tập hợp, 69
thư viện, 61
từ điển, 72
tuple, 48
vòng lặp, 35
vòng lặp for, 50
vòng lặp while, 35
162
TÀI LIỆU THAM KHẢO
[1] Kong, Q., Siauw, T., & Bayen, A. M. (2021). Python Programming and
Numerical Methods - A Guide for Engineers and Scientists. Elsevier Inc.
[2] Swaroop, H. (2019). A Byte of Python.
[3] Python Software Foundation. (2022). Python documentation.
https://docs.python.org/3/
[4] Hill, C. (2020). Learning scientific programming with Python.
Cambridge University Press.
[5] Stephenson, B. (2019). The Python Workbook 2nd. Springer.
[6] Pine, D. J. (2019). Introduction to Python for science and engineering.
CRC Press.
[7]
NumPy
Developers.
(2022).
https://numpy.org/doc/stable/reference/
NumPy
manual.
[8] Kurniawan, A. (2015). Python Programming by Example. PE Press.
163
Giáo trình Lập trình Python căn bản
Trần Nhật Quang, Phạm Văn Khoa
Trường Đại học Sư phạm Kỹ thuật Thành phố Hồ Chí Minh
NHÀ XUẤT BẢN ĐẠI HỌC QUỐC GIA THÀNH PHỐ HỒ CHÍ MINH
Trụ sở:
Phòng 501, Nhà Điều hành ĐHQG-HCM, P. Linh Trung, TP Thủ Đức, TP.HCM.
ĐT: 028 62726361
E-mail: vnuhp@vnuhcm.edu.vn
Website: www.vnuhcmpress.edu.vn
Chịu trách nhiệm xuất bản và nội dung
TS ĐỖ VĂN BIÊN
Biên tập
LÊ THỊ MINH HUỆ
Sửa bản in
THANH HÀ
Trình bày bìa
TRƯỜNG ĐẠI HỌC SƯ PHẠM KỸ THUẬT THÀNH PHỒ HỒ CHÍ MINH
Đối tác liên kết
TRƯỜNG ĐẠI HỌC SƯ PHẠM KỸ THUẬT THÀNH PHỒ HỒ CHÍ MINH
Xuất bản lần thứ 1. Số lượng in: 250 cuốn, khổ 16 x 24cm. Số
XNĐKXB: 1508-2023/CXBIPH/6-24/ĐHQGTPHCM. QĐXB số: 88/QĐNXB cấp ngày 19/5/2023. In tại: Công ty TNHH In & Bao bì Hưng Phú. Địa
chỉ: 162A/1, KP1A, phường An Phú, TP Thuận An, tỉnh Bình Dương. Nộp lưu
chiểu: Năm 2023. ISBN: 978-604-73-9874-4.
Bản quyền tác phẩm đã được bảo hộ bởi Luật Xuất bản và Luật Sở hữu
trí tuệ Việt Nam. Nghiêm cấm mọi hình thức xuất bản, sao chụp, phát tán nội
dung khi chưa có sự đồng ý của tác giả và Nhà xuất bản.
ĐỂ CÓ SÁCH HAY, CẦN CHUNG TAY BẢO VỆ TÁC QUYỀN!
NXB ĐHQG-HCM
ISBN: 978-604-73-9874-4
9 786047 398744
Download