Mục con


3. Giới thiệu sơ về Python

Trong ví dụ say, đầu vào và đầu ra được phân biệt bằng sự hiện diện của dấu nhắc (">>> " và "... "): để lặp lại ví tụ, bạn cần nhập vào mọi thứ 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 một dấu nhắc là kết quả xuất từ trình thông dịch. Lưu ý rằng dấu nhắc thứ (secondary prompt) trên một dòng riêng nó có nghĩa là bạn phải nhận một dòng trống; dòng này dùng để kết thúc một lệnh nhiều dòng.

Nhiều ví dụ trong tài liệu này, ngay cả những ví dụ nhập từ dòng lệnh tương tác, có cả chú thích. Các chú thích trong Python bắt đầu bằng một dấu thăng, "#", và kéo dài tới hết dòng. 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ã, nhưng không phải trong một chuỗi. Một dấu thăng trong một chuỗi chỉ là một dấu thăng.

Một vài ví dụ:

# this is the first comment
SPAM = 1                 # and this is the second comment
                         # ... and now a third!
STRING = "# This is not a comment."


3.1 Dùng Python như là 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à chờ dấu nhắc chính, ">>> ". (Không lâu đâu.)


3.1.1 Số

Trình thông dịch đóng vài trò là một máy tính đơn giản: bạn nhập một biểu thức và nó sẽ trả về giá trị. Cú pháp biểu thức rất dễ hiểu: các toán tử +, -, */ hoạt động như trong hầu hết các ngôn ngữ khác (ví dụ Pascal hay C); dấu ngoặc tròn dùng để gộp nhóm. Ví dụ:

>>> 2+2
4
>>> # This is a comment
... 2+2
4
>>> 2+2  # and a comment on the same line as code
4
>>> (50-5*6)/4
5
>>> # Integer division returns the floor:
... 7/3
2
>>> 7/-3
-3

Dấu bằng ("=") được dùng để gán một giá trị vào một biến. Sau đó, không có giá trị nào được hiện ra trước dấu nhắc tương tác kế:

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

Một giá trị có thể được gán vào nhiều biến cùng một lúc:

>>> x = y = z = 0  # Zero x, y and z
>>> x
0
>>> y
0
>>> z
0

Python hoàn toàn hỗ trợ dấu chấm động; các toán tử với các toán hạng khác kiểu chuyển toán hạng số nguyên thành dấu chấm động:

>>> 3 * 3.75 / 1.5
7.5
>>> 7.0 / 2
3.5

Số phức cũng được hỗ trợ; số ảo được viết với hậu tố "j" hoặc "J". Các số phức với phần thực khác không được viết "(real+imagj)", hoặc có thể được tạo ra với hàm "complex(real, imag)".

>>> 1j * 1J
(-1+0j)
>>> 1j * complex(0,1)
(-1+0j)
>>> 3+1j*3
(3+3j)
>>> (3+1j)*3
(9+3j)
>>> (1+2j)/(1+1j)
(1.5+0.5j)

Các số phức luôn được thể hiện bởi hai số chấm động, phần thực và phần ảo. Để lấy các phần từ một số phức z, dùng z.realz.imag.

>>> a=1.5+0.5j
>>> a.real
1.5
>>> a.imag
0.5

Các hàm chuyển đổi từ chấm động sang số nguyên (float(), int()long()) không dùng được với số phức -- không có một cách chính xác nào để chuyển đổi một số phức thành một số thực. Dùng abs(z) để lấy độ lớn (magnitude) (như là một số chấm động) hoặc z.real để lấy phần thực.

>>> a=3.0+4.0j
>>> float(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: can't convert complex to float; use abs(z)
>>> a.real
3.0
>>> a.imag
4.0
>>> abs(a)  # sqrt(a.real**2 + a.imag**2)
5.0
>>>

Trong chế độ tương tác, biểu thức được in ra cuối cùng được gán vào biến _. Khi bạn dùng Python như là máy tính, nó sẽ giúp bạn tiếp tục các phép tính dễ hơn, 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 coi là chỉ đọc từ phía người dùng. Không nên gán một giá trị vào biến này trực tiếp -- bạn sẽ tạo một biến cục bộ riêng với cùng tên, che đi biến có sẵn với cách thức (behavior) diệu kỳ của nó.


3.1.2 Chuỗi

Ngoài số, Python còn làm việc được với chuỗi, có thể được biểu hiện theo nhiều cách. Chúng có thể được kẹp trong dấu nháy đơn, đôi:

>>> 'spam eggs'
'spam eggs'
>>> 'doesn\'t'
"doesn't"
>>> "doesn't"
"doesn't"
>>> '"Yes," he said.'
'"Yes," he said.'
>>> "\"Yes,\" he said."
'"Yes," he said.'
>>> '"Isn\'t," she said.'
'"Isn\'t," she said.'

Các chuỗi có thể phủ nhiều dòng theo nhiều cách. Các dòng tiếp tục (continuation line) có thể được dùng, với một dấu suỵt huyền là ký tự cuối cùng trên một dòng cho biết rằng dòng kế là sự nối tiếp của dòng này:

hello = "This is a rather long string containing\n\
several lines of text just as you would do in C.\n\
    Note that whitespace at the beginning of the line is\
 significant."

print hello

Lưu ý rằng các dòng mới vẫn cần được chèn trong chuỗi với \n; ký tự dòng mới theo sau dấu suỵt huyền sẽ bị bỏ qua. Ví dụ này sẽ in ra:

This is a rather long string containing
several lines of text just as you would do in C.
    Note that whitespace at the beginning of the line is significant.

Tuy nhiên, nếu ta làm cho chuỗi trực tiếp thành chuỗi ``thô'', các dãy \n sẽ không được chuyển thành các dòng mới, nhưng dấu suỵt huyền ở cuối dòng, và ký tự dòng mới trong nguồn, sẽ đều được thêm vào trong chuỗi như dữ liệu. Cho nên, ví dụ:

hello = r"This is a rather long string containing\n\
several lines of text much as you would do in C."

print hello

sẽ in:

This is a rather long string containing\n\
several lines of text much as you would do in C.

Hoặc, các chuỗi có thể được vây quanh trong một cặp nháy ba: """ hoặc '''. Cuỗi mỗi dòng không cần thêm dấu suỵt huyền khi dùng nháy ba, và chúng sẽ có mặt trong chuỗi.

print """
Usage: thingy [OPTIONS] 
     -h                        Display this usage message
     -H hostname               Hostname to connect to
"""

xuất ra:

Usage: thingy [OPTIONS] 
     -h                        Display this usage message
     -H hostname               Hostname to connect to

Trình thông dịch in ra kết quả của các tác vụ chuỗi theo cùng cách như khi chúng được nhập vào: trong dấu nháy, và với các ký tự dấu nháy hay đặc biệt khác được thoát nghĩa (escape) bằng dấu suỵt huyền, để hiện giá trị thực. Chuỗi được kèm trong dấu nháy đôi nếu chuỗi chứa một dấu nháy đơn và không chứa dấu nháy đôi, ngoài ra nó sẽ được chứa trong các dấu nháy đơn. (Câu lệnh print , được giải thích sau, có thể dùng để viết các chuỗi không có dấu nháy hoặc thoát nghĩa.)

Các chuỗi có thể được nối với nhau với toán tử + , và được lặp lại với *:

>>> word = 'Help' + 'A'
>>> word
'HelpA'
>>> '<' + word*5 + '>'
'<HelpAHelpAHelpAHelpAHelpA>'

Hai chuỗi trực tiếp kế nhau được tự động nối với nhau; dòng đầu tiên bên trên có thể được biết "word = 'Help' 'A'"; việc này chỉ có tác dụng với hai chuỗi trực tiếp (string literal), không có tác dụng với các biểu thức chuỗi bất kỳ khác:

>>> 'str' 'ing'                   #  <-  This is ok
'string'
>>> 'str'.strip() + 'ing'   #  <-  This is ok
'string'
>>> 'str'.strip() 'ing'     #  <-  This is invalid
  File "<stdin>", line 1, in ?
    'str'.strip() 'ing'
                      ^
SyntaxError: invalid syntax

Các chuỗi có thể được chỉ mục (subscript hoặc index); như trong C, ký tự đầu tiên của một chuỗi có chỉ mục 0. Không có kiểu ký tự riêng; một ký tự chỉ đơn giản là một chuỗi có độ dài là một. Như trong Icon, chuỗi con có thể được chỉ định theo cách viết cắt lát (slice notation): hai chỉ mục phân cách bởi một dấu hai chấm.

>>> word[4]
'A'
>>> word[0:2]
'He'
>>> word[2:4]
'lp'

Các chỉ mục cắt lát có giá trị mặc định hữu dụng; chỉ mục đầu tiên có giá trị mặc định là không, chỉ mục thứ hai mặc định là kích thước của chuỗi đang bị cắt.

>>> word[:2]    # The first two characters
'He'
>>> word[2:]    # Everything except the first two characters
'lpA'

Không như C, các chuỗi Python không thể bị thay đổi. Phép gán vào một vị trí chỉ mục trong một chuỗi sẽ gây ra lỗi:

>>> word[0] = 'x'
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: object doesn't support item assignment
>>> word[:1] = 'Splat'
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: object doesn't support slice assignment

Tuy nhiên, việc tạo một chuỗi với nội dung gộp chung cũng dễ và hiệu quả:

>>> 'x' + word[1:]
'xelpA'
>>> 'Splat' + word[4]
'SplatA'

Đây là một tính chất bất biến hữu dụng khác của tác vụ cắt lát: s[:i] + s[i:] bằng s.

>>> word[:2] + word[2:]
'HelpA'
>>> word[:3] + word[3:]
'HelpA'

Các chỉ mục cắt lát giảm sinh (degenerate) được xử lý rất khéo: một chỉ mục quá lớn sẽ được thay bằng kích thước chuỗi, một giới hạn trên nhỏ hơn giới hạn dưới trả về một chuỗi rỗng.

>>> word[1:100]
'elpA'
>>> word[10:]
''
>>> word[2:1]
''

Các chỉ mục có thể là số âm, để bắt đầu đếm từ bên phải. Ví dụ:

>>> word[-1]     # The last character
'A'
>>> word[-2]     # The last-but-one character
'p'
>>> word[-2:]    # The last two characters
'pA'
>>> word[:-2]    # Everything except the last two characters
'Hel'

Nhưng lưu ý rằng -0 thật ra cũng là 0, cho nên nó không bắt đầu đếm từ bên phải!

>>> word[-0]     # (since -0 equals 0)
'H'

Các chỉ mục cắt lát âm ngoài phạm vi thì bị thu ngắn, nhưng đừng thử kiểu này với các chỉ mục một phần từ (không phải cắt lát):

>>> word[-100:]
'HelpA'
>>> word[-10]    # error
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
IndexError: string index out of range

Cách tốt nhất để nhớ hoạt động của cắt lát là nghĩ về các chỉ mục như đang trỏ vào giữa các ký tự, với cạnh trái của ký tự đầu tiên là 0. Sau đó cạnh phải của ký tự cuối cùng của một chuỗi của n ký tự có chỉ mục n, ví dụ:

 +---+---+---+---+---+ 
 | H | e | l | p | A |
 +---+---+---+---+---+ 
 0   1   2   3   4   5 
-5  -4  -3  -2  -1

Các số hàng đầu cho biết vị trí của các chỉ mục 0...5 trong chuỗi; dòng thứ hai cho biết các chỉ mục âm tương ứng. Một lát từ i tới j chứa toàn bộ các ký tự giữa các cạnh đánh số ijtương ứng.

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

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

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

Xem thêm:

Các kiểu dãy
Chuỗi, và các chuỗi Unicode được nhắc đến trong mục kế, là ví dụ của các kiểu dãy, và hỗ trợ các tác vụ chung được hỗ trợ bởi các kiểu đó.
Các phương thức chuỗi
Cả chuỗi và chuỗi Unicode hỗ trợ một số lớn các phương thức nhằm vào chuyển đổi (transform) và tìm kiếm.
Các tác vụ định dạng chuỗi
Các tác vụ định dạng chuỗi được gọi khi các chuỗi và chuỗi Unicode là toán hạng bên trái của toán tử % được bàn đến chi tiết hơn ở đây.


3.1.3 Chuỗi Unicode

Bắt đầu với Python 2.0, một kiểu dữ liệu mới để chứa dữ liệu văn bản được cung cấp cho nhà lập trình: đối tượng Unicode. Nó có thể được dùng để chứa và thay đổi dữ liệu Unicode (xem http://www.unicode.org/) và tích hợp tốt với các đối tượng chuỗi đã có, bằng việc tự chuyển đổi khi cần.

Unicode có lợi điểm là cung cấp một số thứ tự (ordinal) cho mọi ký tự trong các bản thảo dùng trong các văn bản xưa và nay. Trước kia, chỉ có 256 số thứ tự cho các ký tự bản thảo. Các văn bản xưa bị giới hạn vào một trang mã (code page) dùng để ánh xạ các số vào các ký tự bản thảo. Điều này dẫn đến nhiều lẫn lộn đặc biệt là trong ngữ cảnh quốc tế hóa (internationalization, hay được viết tắt là "i18n" -- "i" + 18 ký tự + "n") phần mềm. Unicode giải quyết các vấn đề này bằng các định nghĩa một trang mã cho mọi bản thảo.

Tạo một chuỗi Unicode trong Python dễ như tạo một chuỗi thường:

>>> u'Hello World !'
u'Hello World !'

Ký tự "u" đằng trước dấu nháy cho biết đây là một chuỗi Unicode cần được tạo. Nếu bạn muốn thêm các ký tự đặc biệt trong chuỗi, bạn có thể làm vậy bằng cách viết thoát nghĩa Unicode-Escape của Python. Ví dụ:

>>> u'Hello\u0020World !'
u'Hello World !'

Dãy thoát nghĩa \u0020 cho biết chèn một ký tự Unicode với thứ tự 0x0020 (ký tự khoảng trắng) vào một vị trí đã định.

Các ký tự khác được thông dịch theo thứ tự tương ứng của chúng như là thứ tự Unicode. Nếu bạn có các chuỗi trực tiếp trong bảng mã Latin-1 chuẩn được dùng ở nhiều nước phương Tây, bạn sẽ thấy rằng 256 ký tự đầu của bảng mã Unicode giống như 256 ký tự của Latin-1.

Cho các chuyên gia, Python cũng hỗ trợ các chuỗi Unicode thô. Bạn phải dùng tiền tố 'ur' để bảo Python dùng bảng mã thoát-nghĩa-Unicode-thô (Raw-Unicode-Escape) . Nó sẽ chỉ áp dụng phép chuyển đổi \uXXXX bên trên nếu có một số lẻ các dấu suỵt huyền phía trước ký tự 'u' nhỏ.

>>> ur'Hello\u0020World !'
u'Hello World !'
>>> ur'Hello\\u0020World !'
u'Hello\\\\u0020World !'

Chế độ thô sẽ hữu dụng trong trường hợp bạn phải nhập thật nhiều dấu suỵt huyền, như khi bạn dùng trong các biểu thức chính quy (regular expression).

Ngoài những bảng mã chuẩn này, Python cung cấp một tập hợp các cách khác để tạo các chuỗi Unicode từ một bảng mã đã biết.

Hàm có sẵn unicode() cung cấp truy cập vào tất cả bộ mã/giải mã (codec - COder and DECoder) Unicode đã đăng ký. Một vài bảng mã phổ thông mà các bộ chuyển mã này có thể chuyển gồm Latin-1, ASCII, UTF-8, và UTF-16. Hai bảng mã sau cùng là các bảng mã có kích thước thay đổi và chứa mỗi ký tự Unicode trong một hoặc nhiều byte. Bảng mã mặc định thường được thiết lập là ASCII, nó cho phép các ký tự từ 0 tới 127 và cấm các ký tự khác. Khi một chuỗi Unicode được in, viết vào tập tin, hoặc chuyển với str(), sự chuyển đổi diễn ra với bảng mã mặc định này.

>>> u"abc"
u'abc'
>>> str(u"abc")
'abc'
>>> u"äöü"
u'\xe4\xf6\xfc'
>>> str(u"äöü")
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)

Để chuyển một chuỗi Unicode thành một chuỗi 8-bit bằng một bảng mã nào đó, các đối tượng Unicode cung cấp một phương thức encode() nhận một thông số, tên của bảng mã. Bạn nên dùng tên bảng mã viết thường.

>>> u"äöü".encode('utf-8')
'\xc3\xa4\xc3\xb6\xc3\xbc'

Nếu bạn có dữ liệu trong một bảng mã nào đó và muốn tạo ra một chuỗi Unicode tương ứng từ nó, bạn có thể dùng hàm unicode() với tên bảng mã là thông số thứ hai.

>>> unicode('\xc3\xa4\xc3\xb6\xc3\xbc', 'utf-8')
u'\xe4\xf6\xfc'


3.1.4 Danh sách

Python biết một số kiểu dữ liệu gộp (compound) , dùng để nhóm các giá trị với nhau. Kiểu linh hoạt nhất là danh sách (list), có thể được viết như là một danh sách các giá trị phân cách bởi dấu phẩy ở giữa ngoặc vuông.

>>> a = ['spam', 'eggs', 100, 1234]
>>> a
['spam', 'eggs', 100, 1234]

Cũng như các chỉ mục chuỗi, chỉ mục danh sách bắt đầu từ 0, và danh sách có thể được cắt lát, gộm và vân vân:

>>> a[0]
'spam'
>>> a[3]
1234
>>> a[-2]
100
>>> a[1:-1]
['eggs', 100]
>>> a[:2] + ['bacon', 2*2]
['spam', 'eggs', 'bacon', 4]
>>> 3*a[:3] + ['Boo!']
['spam', 'eggs', 100, 'spam', 'eggs', 100, 'spam', 'eggs', 100, 'Boo!']

Không như chuỗi, là những đối tượng immutable (bất biến, không thể thay đổi), ta có thể thay đổi các phần tử của một danh sách:

>>> a
['spam', 'eggs', 100, 1234]
>>> a[2] = a[2] + 23
>>> a
['spam', 'eggs', 123, 1234]

Gán vào các cắt lát cũng có thể làm được, và nó có thể thay đổi kích thước của danh sách hoặc xóa sách nó.

>>> # Replace some items:
... a[0:2] = [1, 12]
>>> a
[1, 12, 123, 1234]
>>> # Remove some:
... a[0:2] = []
>>> a
[123, 1234]
>>> # Insert some:
... a[1:1] = ['bletch', 'xyzzy']
>>> a
[123, 'bletch', 'xyzzy', 1234]
>>> # Insert (a copy of) itself at the beginning
>>> a[:0] = a
>>> a
[123, 'bletch', 'xyzzy', 1234, 123, 'bletch', 'xyzzy', 1234]
>>> # Clear the list: replace all items with an empty list
>>> a[:] = []
>>> a
[]

Hàm có sẵn len() cũng áp dụng vào danh sách:

>>> len(a)
8

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

>>> q = [2, 3]
>>> p = [1, q, 4]
>>> len(p)
3
>>> p[1]
[2, 3]
>>> p[1][0]
2
>>> p[1].append('xtra')     # See section 5.1
>>> p
[1, [2, 3, 'xtra'], 4]
>>> q
[2, 3, 'xtra']

Lưu ý trong ví dụ, p[1]q thật ra chỉ tới cùng đối tượng! Chúng ta sẽ nói về nghĩa của đối tượng (object semantics) trong các chương sau.


3.2 Những bước đầu lập trình

Dĩ nhiên, chúng ta có dùng Python cho các tác vụ phức tạp khác. Ví dụ ta có thể viết một dãy con ban đầu của dãy Fibonacci như sau:

>>> # Fibonacci series:
... # the sum of two elements defines the next
... a, b = 0, 1
>>> while b < 10:
...       print b
...       a, b = b, a+b
... 
1
1
2
3
5
8

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

Xem Về tài liệu này... về cách đề nghị thay đổi.