3. Giới thiệu sơ lược về Python

Trong các ví dụ dưới đây, đầu vào và đầu ra được phân biệt bởi sự xuất hiện hoặc vắng mặt của các dấu nhắc (>>>...): để thực hiện lại ví dụ, bạn phải nhập mọi thứ phía sau dấu nhắc khi dấu nhắc xuất hiện; các dòng không bắt đầu bằng dấu nhắc là kết quả đầu ra từ trình thông dịch. Lưu ý rằng một dấu nhắc phụ nằm riêng biệt trên một dòng trong ví dụ có nghĩa là bạn phải nhập một dòng trống; điều này được dùng để kết thúc một lệnh gồm nhiều dòng.

Bạn có thể sử dụng nút "Copy" (xuất hiện ở góc trên bên phải khi di chuột qua hoặc chạm vào ví dụ code), nút này sẽ loại bỏ các dấu nhắc và bỏ qua đầu ra, để sao chép và dán các dòng đầu vào vào trình thông dịch của bạn.

Nhiều ví dụ trong tài liệu hướng dẫn này, ngay cả những ví dụ được nhập tại dấu nhắc tương tác, có bao gồm các chú thích. Chú thích trong Python bắt đầu bằng ký tự thăng, #, và kéo dài đến hết dòng vật lý. Một chú thích có thể xuất hiện ở đầu dòng hoặc theo sau khoảng trắng hoặc mã nguồn, nhưng không nằm trong một chuỗi ký tự. Một ký tự thăng nằm trong một chuỗi ký tự chỉ đơn thuần là một ký tự thăng. Vì chú thích dùng để làm rõ mã nguồn và không được Python thông dịch, nên bạn có thể bỏ qua chúng khi nhập các ví dụ.

Một số ví dụ:

# đây là chú thích đầu tiên
spam = 1 # và đây là chú thích thứ hai
# ... và bây giờ là chú thích thứ ba!
text = "# Đây không phải là chú thích vì nó nằm trong dấu ngoặc kép."

3.1. Sử dụng Python như một chiếc máy tính

Hãy thử một vài lệnh Python đơn giản. Khởi động trình thông dịch và đợi dấu nhắc chính, >>>. (Việc này sẽ không mất nhiều thời gian.)

3.1.1. Số học

Trình thông dịch hoạt động như một chiếc máy tính đơn giản: bạn có thể nhập một biểu thức vào đó và nó sẽ xuất ra giá trị. Cú pháp biểu thức rất đơn giản: các toán tử +, -, */ có thể được sử dụng để thực hiện tính toán; dấu ngoặc đơn (()) có thể được sử dụng để nhóm các phép tính. Ví dụ:

>>> 2 + 2
4
>>> 50 - 5*6
20
>>> (50 - 5*6) / 4
5.0
>>> 8 / 5 # phép chia luôn trả về một số dấu phẩy động
1.6

Các số nguyên (ví dụ: 2, 4, 20) thuộc kiểu int, các số có phần thập phân (ví dụ: 5.0, 1.6) thuộc kiểu float. Chúng ta sẽ tìm hiểu thêm về các kiểu dữ liệu số ở phần sau của bài hướng dẫn.

Phép chia (/) luôn trả về một số thực. Để thực hiện phép chia lấy phần nguyên và nhận kết quả là một số nguyên, bạn có thể sử dụng toán tử //; để tính số dư, bạn có thể sử dụng %:

>>> 17 / 3 # phép chia thông thường trả về một số thực
5.666666666666667
>>>
>>> 17 // 3 # phép chia lấy phần nguyên loại bỏ phần thập phân
5
>>> 17 % 3 # toán tử % trả về số dư của phép chia
2
>>> 5 * 3 + 2 # thương nguyên * số chia + số dư
17

Với Python, có thể sử dụng toán tử ** để tính lũy thừa [1]:

>>> 5 ** 2 # 5 bình phương
25
>>> 2 ** 7 # 2 lũy thừa 7
128

Dấu bằng (=) được dùng để gán một giá trị cho một biến. Sau đó, không có kết quả nào được hiển thị trước dấu nhắc tương tác tiếp theo:

>>> width = 20
>>> height = 5 * 9
>>> width * height
900

Nếu một biến chưa được "định nghĩa" (được gán một giá trị), việc cố gắng sử dụng nó sẽ gây ra lỗi:

>>> n # thử truy cập một biến chưa được định nghĩa
Traceback (most recent call last):
File "1", line 1, in 2
NameError: name 'n' is not defined

Có sự hỗ trợ đầy đủ cho số dấu phẩy động; các toán tử có các toán hạng thuộc kiểu hỗn hợp sẽ chuyển đổi toán hạng số nguyên sang số dấu phẩy động:

>>> 4 * 3.75 - 1
14.0

Ở chế độ tương tác, biểu thức được in ra cuối cùng sẽ được gán cho biến _. Điều này có nghĩa là khi bạn sử dụng Python như một chiếc máy tính để bàn, việc tiếp tục các phép tính sẽ dễ dàng hơn phần nào, ví dụ:

>>> tax = 12.5 / 100
>>> price = 100.50
>>> price * tax
12.5625
>>> price + _
113.0625
>>> round(_, 2)
113.06

Biến này nên được người dùng xử lý ở chế độ chỉ đọc. Đừng gán giá trị cho nó một cách rõ ràng --- bạn sẽ tạo ra một biến cục bộ độc lập có cùng tên, làm che khuất biến tích hợp sẵn với hành vi đặc biệt của nó.

Ngoài intfloat, Python còn hỗ trợ các kiểu số khác, chẳng hạn như DecimalFraction. Python cũng tích hợp sẵn hỗ trợ cho số phức, và sử dụng hậu tố j hoặc J để chỉ định phần ảo (ví dụ: 3+5j).

3.1.2. Văn bản

Python có thể xử lý văn bản (được đại diện bởi kiểu str, hay còn gọi là "chuỗi") cũng như các con số. Điều này bao gồm các ký tự "!", các từ "rabbit", tên riêng "Paris", các câu "Got your back.", v.v, "Yay! :)". Chúng có thể được bao quanh bởi dấu ngoặc đơn ('...') hoặc dấu ngoặc kép ("...") với cùng một kết quả [2].

>>> 'spam eggs' # dấu ngoặc đơn
'spam eggs'
>>> "Paris rabbit got your back :)! Yay!" # dấu ngoặc kép
'Paris rabbit got your back :)! Yay!'
>>> '1975' # các chữ số nằm trong dấu ngoặc kép cũng là chuỗi
'1975'

Để trích dẫn một dấu ngoặc, chúng ta cần thoát nó bằng cách thêm dấu \ phía trước. Ngoài ra, chúng ta có thể sử dụng loại dấu ngoặc kép còn lại:

>>> 'doesn\'t' # sử dụng \' để thoát dấu ngoặc đơn...
"doesn't"
>>> "doesn't" # ...hoặc sử dụng dấu ngoặc kép để thay thế
"doesn't"
>>> '"Yes," they said.'
'"Yes," they said.'
>>> "\"Yes,\" they said."
'"Yes," they said.'
>>> '"Isn\'t," they said.'
'"Isn\'t," they said.'

Trong cửa sổ dòng lệnh Python, định nghĩa chuỗi và chuỗi kết quả xuất ra có thể trông khác nhau. Hàm print() tạo ra kết quả đầu ra dễ đọc hơn bằng cách loại bỏ các dấu ngoặc bao quanh và in ra các ký tự đã được thoát và các ký tự đặc biệt:

>>> s = 'First line.\nSecond line.' # \n có nghĩa là dòng mới
>>> s # nếu không có print(), các ký tự đặc biệt sẽ được bao gồm trong chuỗi
'First line.\nSecond line.'
>>> print(s) # với print(), các ký tự đặc biệt được thông dịch, nên \n tạo ra dòng mới
First line.
Second line.

Nếu bạn không muốn các ký tự đứng sau dấu \ bị diễn giải thành các ký tự đặc biệt, bạn có thể sử dụng chuỗi thô bằng cách thêm một chữ r vào trước dấu ngoặc đầu tiên:

>>> print('C:\this\name') # ở đây \t có nghĩa là tab, \n có nghĩa là dòng mới
C: his
ame
>>> print(r'C:\this\name') # lưu ý chữ r trước dấu ngoặc
C:\this\name

Có một khía cạnh tế nhị đối với chuỗi thô: một chuỗi thô không được kết thúc bằng một số lẻ các ký tự \; xem mục câu hỏi thường gặp để biết thêm thông tin và các cách xử lý.

Các chuỗi ký tự có thể kéo dài trên nhiều dòng. Một cách là sử dụng dấu ngoặc ba: """...""" hoặc '``'''...'''. Các tự kết thúc dòng sẽ tự động được bao gồm trong chuỗi, nhưng thể ngăn chặn điều này bằng cách thêm một dấu ``\ ở cuối dòng. Trong ví dụ sau, ký tự dòng mới đầu tiên không được bao gồm:

>>> print("""\
... Usage: thingy [OPTIONS]
... -h Hiển thị thông báo hướng dẫn này
... -H hostname Tên máy chủ để kết nối tới
... """)
Usage: thingy [OPTIONS]
-h Hiển thị thông báo hướng dẫn này
-H hostname Tên máy chủ để kết nối tới

>>>

Chuỗi có thể được nối với nhau (dán lại với nhau) bằng toán tử +, và lặp lại với toán tử *:

>>> # 3 lần 'un', theo sau là 'ium'
>>> 3 * 'un' + 'ium'
'unununium'

Hai hoặc nhiều chuỗi ký tự (tức là những chuỗi nằm trong dấu ngoặc) đặt cạnh nhau sẽ được tự động nối lại với nhau.

>>> 'Py' 'thon'
'Python'

Tính năng này đặc biệt hữu ích khi bạn muốn ngắt các chuỗi dài:

>>> text = ('Đặt nhiều chuỗi trong dấu ngoặc đơn '
... 'để chúng được nối lại với nhau.')
>>> text
'Đặt nhiều chuỗi trong dấu ngoặc đơn để chúng được nối lại với nhau.'

Tuy nhiên, điều này chỉ hoạt động với hai chuỗi ký tự thuần, không hoạt động với các biến hoặc biểu thức:

>>> prefix = 'Py'
>>> prefix 'thon' # không thể nối một biến và một chuỗi ký tự thuần
File "1", line 1
prefix 'thon'
^^^^^^
SyntaxError: invalid syntax
>>> ('un' * 3) 'ium'
File "2", line 1
('un' * 3) 'ium'
^^^^^
SyntaxError: invalid syntax

Nếu bạn muốn nối các biến hoặc một biến với một chuỗi ký tự thuần, hãy sử dụng +:

>>> prefix + 'thon'
'Python'

Chuỗi có thể được đánh chỉ số (indexed), với ký tự đầu tiên có chỉ số là 0. Không có kiểu ký tự riêng biệt; một ký tự đơn giản là một chuỗi có kích thước bằng một:

>>> word = 'Python'
>>> word[0] # ký tự ở vị trí 0
'P'
>>> word[5] # ký tự ở vị trí 5
'n'

Chỉ số cũng có thể là số âm, để bắt đầu đếm từ phía bên phải:

>>> word[-1] # ký tự cuối cùng
'n'
>>> word[-2] # ký tự áp chót
'o'
>>> word[-6]
'P'

Lưu ý rằng vì -0 cũng giống như 0, nên các chỉ số âm bắt đầu từ -1.

Ngoài việc đánh chỉ số, việc cắt chuỗi slicing cũng được hỗ trợ. Trong khi đánh chỉ số được dùng để lấy các ký tự riêng lẻ, cắt chuỗi cho phép bạn lấy một chuỗi con:

>>> word[0:2] # các ký tự từ vị trí 0 (bao gồm) đến 2 (loại trừ)
'Py'
>>> word[2:5] # các ký tự từ vị trí 2 (bao gồm) đến 5 (loại trừ)
'tho'

Các chỉ số cắt chuỗi có các giá trị mặc định hữu ích; chỉ số đầu tiên nếu bị bỏ trống sẽ mặc định là 0, chỉ số thứ hai nếu bị bỏ trống sẽ mặc định là độ dài của chuỗi đang được cắt.

>>> word[:2] # ký tự từ đầu đến vị trí 2 (loại trừ)
'Py'
>>> word[4:] # ký tự từ vị trí 4 (bao gồm) đến hết
'on'
>>> word[-2:] # ký tự từ vị trí áp chót (bao gồm) đến hết
'on'

Lưu ý rằng điểm bắt đầu luôn được bao gồm, và điểm kết thúc luôn bị loại trừ. Điều này đảm bảo rằng s[:i] + s[i:] luôn luôn bằng s:

>>> word[:2] + word[2:]
'Python'
>>> word[:4] + word[4:]
'Python'

Cách để ghi nhớ việc cắt chuỗi hoạt động như thế nào là hãy coi các chỉ số như những điểm nằm giữa các ký tự, với mép trái của ký tự đầu tiên được đánh số 0. Khi đó, mép phải của ký tự cuối cùng trong một chuỗi có n ký tự sẽ có chỉ số là n, ví dụ:

 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
 0   1   2   3   4   5   6
-6  -5  -4  -3  -2  -1

Dòng số đầu tiên cho biết vị trí của các chỉ số 0...6 trong chuỗi; dòng thứ hai cho biết các chỉ số âm tương ứng. Đoạn cắt từ i đến j bao gồm tất cả các ký tự nằm giữa các cạnh được đánh dấu tương ứng là ij.

Đối với các chỉ số không âm, độ dài của một đoạn cắt là hiệu của các chỉ số, nếu cả hai đều nằm trong phạm vi. Ví dụ, độ dài của word[1:3] là 2.

Việc cố gắng sử dụng một chỉ số quá lớn sẽ dẫn đến lỗi:

>>> word[42] # từ này chỉ có 6 ký tự
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range

Tuy nhiên, các chỉ số cắt nằm ngoài phạm vi được xử lý một cách linh hoạt khi được sử dụng để cắt chuỗi:

>>> word[4:42]
'on'
>>> word[42:]
''

Chuỗi Python không thể thay đổi --- chúng có tính bất biến immutable. Do đó, việc gán giá trị vào một vị trí chỉ số trong chuỗi sẽ dẫn đến lỗi:

>>> word[0] = 'J'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> word[2:] = 'py'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment

Nếu bạn cần một chuỗi khác, bạn nên tạo một chuỗi mới:

>>> 'J' + word[1:]
'Jython'
>>> word[:2] + 'py'
'Pypy'

Hàm tích hợp sẵn len() trả về độ dài của một chuỗi:

>>> s = 'supercalifragilisticexpialidocious'
>>> len(s)
34

Xem thêm

Text Sequence Type --- str

Chuỗi là các ví dụ về kiểu tuần tự, và hỗ trợ các thao tác phổ biến được hỗ trợ bởi các kiểu dữ liệu này.

String Methods

Chuỗi hỗ trợ một số lượng lớn các phương thức cho các phép biến đổi cơ bản và tìm kiếm.

f-strings

Các chuỗi ký tự có chứa các biểu thức nhúng.

Format string syntax

Thông tin về định dạng chuỗi với str.format().

printf-style String Formatting

Các thao tác định dạng cũ được gọi khi chuỗi là toán hạng bên trái của toán tử % được mô tả chi tiết hơn tại đây.

3.1.3. Lists

Python hỗ trợ một số kiểu dữ liệu phức hợp, được sử dụng để nhóm các giá trị khác lại với nhau. Kiểu linh hoạt nhất là list, có thể được viết dưới dạng một danh sách các giá trị (phần tử) ngăn cách bởi dấu phẩy nằm giữa các dấu ngoặc vuông. Danh sách có thể chứa các phần tử thuộc nhiều kiểu khác nhau, nhưng thông thường các phần tử sẽ có cùng một kiểu dữ liệu.

>>> squares = [1, 4, 9, 16, 25]
>>> squares
[1, 4, 9, 16, 25]

Giống như chuỗi (và tất cả các kiểu dữ liệu tuần tự sequence khác), danh sách có thể được đánh chỉ số và cắt lát:

>>> squares[0] # đánh chỉ số trả về phần tử
1
>>> squares[-1]
25
>>> squares[-3:] # cắt lát trả về một danh sách mới
[9, 16, 25]

List cũng hỗ trợ các thao tác như nối chuỗi:

>>> squares + [36, 49, 64, 81, 100]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Khác với chuỗi vốn có tính bất biến immutable, list là kiểu dữ liệu có thể thay đổi mutable, nghĩa là có thể thay đổi nội dung của chúng:

>>> cubes = [1, 8, 27, 65, 125] # có gì đó sai ở đây
>>> 4 ** 3 # lập phương của 4 là 64, không phải 65!
64
>>> cubes[3] = 64 # thay thế giá trị sai
>>> cubes
[1, 8, 27, 64, 125]

Bạn cũng có thể thêm các phần tử mới vào cuối danh sách bằng cách sử dụng phương thức list.append() (chúng ta sẽ tìm hiểu kỹ hơn về các phương thức sau):

>>> cubes.append(216) # thêm lập phương của 6
>>> cubes.append(7 ** 3) # và lập phương của 7
>>> cubes
[1, 8, 27, 64, 125, 216, 343]

Phép gán đơn giản trong Python không bao giờ sao chép dữ liệu. Khi bạn gán một danh sách cho một biến, biến đó sẽ tham chiếu đến danh sách hiện có. Mọi thay đổi bạn thực hiện đối với danh sách thông qua một biến sẽ được nhìn thấy thông qua tất cả các biến khác tham chiếu đến nó.:

>>> rgb = ["Red", "Green", "Blue"]
>>> rgba = rgb
>>> id(rgb) == id(rgba) # chúng tham chiếu đến cùng một đối tượng
True
>>> rgba.append("Alph")
>>> rgb
["Red", "Green", "Blue", "Alph"]

Tất cả các thao tác cắt lát đều trả về một danh sách mới chứa các phần tử được yêu cầu. Điều này có nghĩa là lát cắt sau đây trả về một bản sao nông của danh sách:

>>> correct_rgba = rgba[:]
>>> correct_rgba[-1] = "Alpha"
>>> correct_rgba
["Red", "Green", "Blue", "Alpha"]
>>> rgba
["Red", "Green", "Blue", "Alph"]

Việc gán cho các lát cắt cũng có thể thực hiện được, và điều này thậm chí có thể thay đổi kích thước của danh sách hoặc xóa sạch danh sách đó hoàn toàn:

>>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> letters
['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> # thay thế một số giá trị
>>> letters[2:5] = ['C', 'D', 'E']
>>> letters
['a', 'b', 'C', 'D', 'E', 'f', 'g']
>>> # bây giờ loại bỏ chúng
>>> letters[2:5] = []
>>> letters
['a', 'b', 'f', 'g']
>>> # xóa sạch danh sách bằng cách thay thế tất cả các phần tử bằng một danh sách trống
>>> letters[:] = []
>>> letters
[]

Hàm tích hợp sẵn len() cũng áp dụng cho danh sách:

>>> letters = ['a', 'b', 'c', 'd']
>>> len(letters)
4

Có thể lồng các danh sách vào nhau (tạo các danh sách chứa các danh sách khác), ví dụ:

>>> a = ['a', 'b', 'c']
>>> n = [1, 2, 3]
>>> x = [a, n]
>>> x
[['a', 'b', 'c'], [1, 2, 3]]
>>> x[0]
['a', 'b', 'c']
>>> x[0][1]
'b'

3.2. Những bước đầu tiên hướng tới lập trình

Tất nhiên, chúng ta có thể sử dụng Python cho những tác vụ phức tạp hơn là chỉ cộng hai với hai. Ví dụ, chúng ta có thể viết một phân đoạn đầu tiên của dãy Fibonacci như sau:

>>> # Dãy Fibonacci:
>>> # tổng của hai phần tử xác định phần tử tiếp theo
>>> a, b = 0, 1
>>> while a < 10:
... print(a)
... a, b = b, a+b
...
0
1
1
2
3
5
8

Ví dụ này giới thiệu một vài tính năng mới.

  • Dòng đầu tiên chứa một phép gán đa thức: các biến ab nhận đồng thời các giá trị mới là 0 và 1. Ở dòng cuối cùng, điều này được lặp lại, chứng minh rằng tất cả các biểu thức ở vế phải đều được tính toán trước khi bất kỳ phép gán nào diễn ra. Các biểu thức vế phải được tính toán từ trái sang phải.

  • Vòng lặp while thực thi chừng nào điều kiện (ở đây là: a < 10) còn đúng. Trong Python, giống như trong C, bất kỳ giá trị số nguyên khác không nào cũng là true; số không là false. Điều kiện cũng có thể là một chuỗi hoặc giá trị danh sách, thực tế là bất kỳ kiểu tuần tự nào; bất cứ thứ gì có độ dài khác không là true, các tuần tự rỗng là false. Phép thử được sử dụng trong ví dụ là một phép so sánh đơn giản. Các toán tử so sánh tiêu chuẩn được viết giống như trong C: < (nhỏ hơn), > (lớn hơn), == (bằng), <= (nhỏ hơn hoặc bằng), >= (lớn hơn hoặc bằng) và != (khác).

  • Thân của vòng lặp được thụt lề: thụt lề là cách Python dùng để nhóm các câu lệnh. Tại cửa sổ tương tác, bạn phải nhập một phím tab hoặc (các) khoảng trắng cho mỗi dòng thụt lề. Trong thực tế, bạn sẽ chuẩn bị các đầu vào phức tạp hơn cho Python bằng một trình soạn thảo văn bản; tất cả các trình soạn thảo văn bản tốt đều có tính năng tự động thụt lề. Khi một câu lệnh phức hợp được nhập theo cách tương tác, nó phải được theo sau bởi một dòng trống để báo hiệu kết thúc (vì bộ phân tích cú pháp không thể đoán được khi nào bạn đã nhập dòng cuối cùng). Lưu ý rằng mỗi dòng trong một khối cơ bản phải được thụt lề với cùng một khoảng cách như nhau.

  • Hàm print() ghi lại giá trị của (các) đối số được truyền vào. Nó khác với việc chỉ viết biểu thức bạn muốn (như chúng ta đã làm trước đó trong các ví dụ về máy tính) ở cách nó xử lý nhiều đối số, các đại lượng số thực dấu phẩy động và chuỗi. Chuỗi được in ra mà không có dấu ngoặc kép, và một khoảng trắng được chèn giữa các phần tử, nhờ đó bạn có thể định dạng mọi thứ đẹp mắt như thế này:

    >>> i = 256*256
    >>> print('Giá trị của i là', i)
    Giá trị của i là 65536
    

    Đối số từ khóa end có thể được sử dụng để tránh xuống dòng sau khi xuất dữ liệu, hoặc kết thúc kết quả đầu ra bằng một chuỗi khác:

    >>> a, b = 0, 1
    >>> while a < 1000:
    ...     print(a, end=',')
    ...     a, b = b, a+b
    ...
    0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,
    

Chú thích