3. Giới thiệu không chính thức về Python

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

Có thể dùng nút "Sao chép" (xuất hiện ở góc trên bên phải khi di chuột hoặc chạm vào ví dụ mã) để sao chép và dán các dòng đầu vào vào trình thông dịch; nút này tự động loại bỏ dấu nhắc và bỏ qua phần đầu ra.

Nhiều ví dụ trong tài liệu này, kể cả những ví dụ gõ tại dấu nhắc tương tác, đều có chú thích. Chú thích trong Python bắt đầu bằng ký tự băm # và kéo dài đến cuối dòng vật lý. Chú thích có thể xuất hiện ở đầu dòng, sau khoảng trắng hoặc sau mã, nhưng không nằm bên trong chuỗi ký tự. Ký tự băm nằm trong chuỗi ký tự chỉ là ký tự băm thông thường. Vì chú thích dùng để làm rõ mã và Python không diễn giải chúng, có thể bỏ qua chú thích khi gõ lại ví dụ.

Một số ví dụ:

# đây là bình luận đầu tiên
spam = 1  # và đây là bình luận thứ hai
          # ... và bây giờ là bình luận thứ ba!
text = "# Đây không phải là bình luận vì nó nằm trong dấu nháy."

3.1. Sử dụng Python làm máy tính

Hãy thử 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 >>> (sẽ không lâu).

3.1.1. Số

Trình thông dịch hoạt động như một máy tính đơn giản: gõ biểu thức vào và nó sẽ in ra giá trị. Cú pháp biểu thức rất rõ ràng: các toán tử +, -, */ dùng cho phép tính số học; dấu ngoặc đơn (()) dùng để nhóm. Ví dụ:

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

Số nguyên (ví dụ 2, 4, 20) có kiểu int, còn số có phần thập phân (ví dụ 5.0, 1.6) có kiểu float. Chúng ta sẽ tìm hiểu thêm về các kiểu số ở phần sau.

Phép chia (/) luôn trả về số float. Để thực hiện floor division và nhận kết quả là số nguyên, hãy dùng toán tử //; để tính phần dư, dùng %:

>>> 17 / 3  # phép chia thông thường trả về số float
5.666666666666667
>>>
>>> 17 // 3  # phép chia nguyên bỏ phần phân số
5
>>> 17 % 3  # toán tử % trả về phần dư của phép chia
2
>>> 5 * 3 + 2  # thương nguyên * số chia + số dư
17

Trong Python, có thể dùng toán tử ** để tính luỹ thừa [1]:

>>> 5 ** 2  # 5 bình phương
25
>>> 2 ** 7  # 2 luỹ thừa 7
128

Dấu bằng (=) dùng để gán giá trị cho biến. Sau phép gán, không có kết quả nào 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 biến chưa được "định nghĩa" (chưa được gán giá trị), việc sử dụng nó sẽ gây lỗi:

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

Python hỗ trợ đầy đủ số dấu phẩy động; với các toán tử có toán hạng khác kiểu nhau, toán hạng số nguyên sẽ được chuyển sang dấu phẩy động:

>>> 4 * 3.75 - 1
14.0

Trong chế độ tương tác, biểu thức in ra cuối cùng sẽ được gán cho biến _. Nhờ vậy, khi dùng Python làm máy tính để bàn, việc tiếp nối các phép tính trở nên tiện lợi hơn, ví dụ:

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

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

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

3.1.2. Văn bản

Ngoài số, Python còn có thể xử lý văn bản (biểu diễn bằng kiểu str, còn gọi là "chuỗi"). Chuỗi có thể là ký tự "!", từ "rabbit", tên "Paris", câu "Got your back.", v.v. "Yay! :)". Chuỗi có thể được đặt trong dấu nháy đơn ('...') hoặc dấu nháy kép ("...") với kết quả như nhau [2].

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

Để đặt dấu nháy bên trong chuỗi đang dùng cùng loại dấu nháy đó, cần "thoát" nó bằng cách đặt \ phía trước. Hoặc có thể dùng loại dấu nháy còn lại:

>>> 'doesn\'t'  # dùng \' để thoát dấu nháy đơn...
"doesn't"
>>> "doesn't"  # ...hoặc dùng dấu nháy kép thay vào
"doesn't"
>>> '"Yes," they said.'
'"Yes," they said.'
>>> "\"Yes,\" they said."
'"Yes," they said.'
>>> '"Isn\'t," they said.'
'"Isn\'t," they said.'

Trong shell Python, chuỗi khai báo và chuỗi hiển thị có thể trông khác nhau. Hàm print() cho đầu ra dễ đọc hơn bằng cách bỏ dấu nháy bao quanh và diễn giải các ký tự thoát cũng như ký tự đặc biệt:

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

Nếu không muốn các ký tự đi sau \ được hiểu là ký tự đặc biệt, có thể dùng raw string bằng cách thêm r trước dấu nháy mở đầu:

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

Có một điểm cần lưu ý về raw string: raw string không được kết thúc bằng số lẻ ký tự \; xem mục FAQ để biết thêm thông tin và cách khắc phục.

Chuỗi ký tự có thể trải dài nhiều dòng. Một cách là dùng dấu nháy ba: """...""" hoặc '''...'''. Các ký tự xuống dòng sẽ được đưa tự động vào chuỗi, nhưng có thể ngăn điều này bằng cách thêm \ ở cuối dòng. Trong ví dụ dưới đây, ký tự xuống dòng ở đầu sẽ không được đưa vào:

>>> print("""\
... Usage: thingy [OPTIONS]
...      -h                        Display this usage message
...      -H hostname               Hostname to connect to
... """)
Usage: thingy [OPTIONS]
     -h                        Display this usage message
     -H hostname               Hostname to connect to

>>>

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

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

Hai hoặc nhiều string literal (tức là các chuỗi nằm giữa dấu nháy) đứng cạnh nhau sẽ tự động được nối lại.

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

Tính năng này đặc biệt hữu ích khi cần chia nhỏ chuỗi dài:

>>> text = ('Put several strings within parentheses '
...         'to have them joined together.')
>>> text
'Put several strings within parentheses to have them joined together.'

Tuy nhiên, cách này chỉ áp dụng cho hai chuỗi ký tự, không áp dụng cho biến hay biểu thức:

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

Nếu muốn nối các biến, hoặc nối một biến với một chuỗi ký tự, hãy dùng +:

>>> prefix + 'thon'
'Python'

Chuỗi có thể được truy cập theo chỉ số (indexing), với ký tự đầu tiên có chỉ số 0. Python không có kiểu ký tự riêng; một ký tự chỉ đơn giản là chuỗi có độ dài 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, khi đó đếm từ bên phải:

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

Lưu ý: vì -0 bằng 0, nên chỉ số âm bắt đầu từ -1.

Ngoài truy cập theo chỉ số, Python còn hỗ trợ slicing (cắt lát). Nếu truy cập theo chỉ số dùng để lấy từng ký tự riêng lẻ, thì slicing cho phép lấy cả một chuỗi con:

>>> word[0:2]  # ký tự từ vị trí 0 (bao gồm) đến 2 (không bao gồm)
'Py'
>>> word[2:5]  # ký tự từ vị trí 2 (bao gồm) đến 5 (không bao gồm)
'tho'

Chỉ số lát cắt có các giá trị mặc định hữu ích: bỏ trống chỉ số đầu thì mặc định là 0, bỏ trống chỉ số thứ hai thì mặc định là độ dài của chuỗi đang cắt.

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

Lưu ý: điểm đầu luôn được bao gồm, điểm cuối luôn bị loại trừ. Nhờ vậy s[:i] + s[i:] luôn bằng s:

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

Một cách để nhớ cách lát cắt hoạt động là hình dung các chỉ số trỏ vào khoảng giữa các ký tự, với cạnh trái của ký tự đầu tiên được đánh số 0. Khi đó cạnh phải của ký tự cuối trong chuỗi n ký tự có chỉ số n, ví dụ:

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

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

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

Dùng chỉ số vượt quá phạm vi sẽ gây lỗi:

>>> word[42]  # chuỗi 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, khi dùng cho lát cắt, các chỉ số nằm ngoài phạm vi lại được xử lý một cách linh hoạt:

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

Chuỗi trong Python không thể thay đổi --- chúng là immutable. Do đó, gán giá trị vào một vị trí trong chuỗi sẽ gây 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 cần chuỗi khác, hãy 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 chuỗi:

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

Xem thêm

Loại chuỗi văn bản --- str

Chuỗi là một ví dụ của sequence type và hỗ trợ các thao tác chung của nhóm kiểu này.

Phương thức chuỗi

Chuỗi hỗ trợ nhiều method phục vụ các thao tác biến đổi và tìm kiếm cơ bản.

dây f

Chuỗi ký tự có nhúng biểu thức bên trong.

Cú pháp định dạng chuỗi

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

Định dạng chuỗi kiểu printf

Các thao tác định dạng kiểu 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 tại đây.

3.1.3. Danh sách

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

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

Giống như chuỗi (và mọi kiểu sequence tích hợp sẵn khác), list có thể được truy cập theo chỉ số và cắt lát:

>>> squares[0]  # truy cập theo chỉ số trả về phần tử
1
>>> squares[-1]
25
>>> squares[-3:]  # cắt lát trả về list mới
[9, 16, 25]

List cũng hỗ trợ các thao tác như phép nố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 là immutable), list là kiểu mutable, nghĩa là có thể thay đổi nội dung của list:

>>> 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]

Cũng có thể thêm phần tử mới vào cuối list bằng method list.append() (method sẽ được giới thiệu kỹ hơn ở phần 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 thuần trong Python không bao giờ sao chép dữ liệu. Khi gán một list cho biến, biến đó tham chiếu tới chính list đã có sẵn. Mọi thay đổi trên list thông qua một biến đều hiển thị qua mọi biến khác cùng tham chiếu tới list đó.:

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

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

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

Cũng có thể gán giá trị vào lát cắt, và thao tác này thậm chí có thể thay đổi kích thước của list hoặc xoá sạch list:

>>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> letters
['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> # thay thế vài giá trị
>>> letters[2:5] = ['C', 'D', 'E']
>>> letters
['a', 'b', 'C', 'D', 'E', 'f', 'g']
>>> # giờ thì xoá chúng
>>> letters[2:5] = []
>>> letters
['a', 'b', 'f', 'g']
>>> # xoá list bằng cách thay mọi phần tử bằng một list rỗng
>>> letters[:] = []
>>> letters
[]

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

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

Cũng có thể lồng list (tạo list chứa các list 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 tới lập trình

Dĩ nhiên, chúng ta có thể dùng Python cho những tác vụ phức tạp hơn phép cộng hai số đơn giản. Ví dụ, có thể viết đoạn đầu 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 nhiều biến (multiple assignment): hai biến ab đồng thời nhận giá trị mới 0 và 1. Dòng cuối cùng cũng dùng cách này, cho thấy mọi biểu thức ở vế phải đều được tính trước khi phép gán diễn ra. Các biểu thức ở vế phải được tính từ trái sang phải.

  • Vòng lặp while chạy chừng nào điều kiện (ở đây là a < 10) còn đúng. Trong Python, cũng như trong C, mọi số nguyên khác 0 đều được xem là đúng; 0 là sai. Điều kiện cũng có thể là giá trị chuỗi, list, hay bất kỳ sequence nào; mọi giá trị có độ dài khác 0 đều đúng, sequence rỗng là sai. Phép kiểm tra trong ví dụ này là một phép so sánh đơn giản. Các toán tử so sánh 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 nhóm các câu lệnh. Tại dấu nhắc tương tác, cần gõ tab hoặc các khoảng trắng cho mỗi dòng thụt lề. Trong thực tế, đầu vào phức tạp hơn cho Python thường được soạn bằng trình soạn thảo văn bản; mọi trình soạn thảo tử tế đều có tính năng thụt lề tự động. Khi nhập một câu lệnh ghép ở chế độ tương tác, cần kết thúc nó bằng một dòng trống để báo hiệu đã xong (vì bộ phân tích cú pháp không thể đoán khi nào dòng cuối được gõ). Lưu ý: mọi dòng trong cùng một khối cơ bản phải được thụt lề cùng một lượng.

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

    >>> i = 256*256
    >>> print('The value of i is', i)
    The value of i is 65536
    

    Đối số từ khoá end có thể dùng để bỏ ký tự xuống dòng sau đầu ra, hoặc để kết thúc đầ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 cuối trang