Giới thiệu về Python

Prelude

Chào mừng bạn đến với hướng dẫn trực tuyến của Google về Python. Khoá học này dựa trên khoá học Python nhập môn được cung cấp nội bộ. Như đã đề cập trên trang thiết lập, tài liệu này đề cập đến Python 3.

Nếu bạn đang tìm kiếm một khoá học MOOC bổ trợ, hãy thử các khoá học của Udacity và Coursera (giới thiệu về lập trình [dành cho người mới bắt đầu] hoặc giới thiệu về Python). Cuối cùng, nếu bạn đang tìm kiếm nội dung học tập trực tuyến theo tiến độ riêng mà không cần xem video, hãy thử những nội dung được liệt kê ở cuối bài đăng này. Mỗi nội dung đều có nội dung học tập cũng như một trình thông dịch Python tương tác mà bạn có thể thực hành. "Trình thông dịch" mà chúng tôi đề cập đến là gì? Bạn sẽ biết được câu trả lời trong phần tiếp theo!

Giới thiệu về ngôn ngữ

Python là một ngôn ngữ động, được diễn giải (được biên dịch bằng mã byte). Không có khai báo kiểu của biến, tham số, hàm hoặc phương thức trong mã nguồn. Điều này giúp mã ngắn gọn và linh hoạt, đồng thời bạn sẽ mất tính năng kiểm tra kiểu thời gian biên dịch của mã nguồn. Python theo dõi các loại của tất cả các giá trị tại thời gian chạy và gắn cờ mã không có ý nghĩa khi mã đó chạy.

Một cách hiệu quả để xem cách hoạt động của mã Python là chạy trình thông dịch Python và nhập mã ngay vào đó. Nếu bạn có câu hỏi như "Điều gì sẽ xảy ra nếu tôi thêm một int vào một list?", thì chỉ cần nhập câu hỏi đó vào trình thông dịch Python là bạn có thể nhanh chóng biết được điều gì sẽ xảy ra. (Xem bên dưới để biết điều gì thực sự xảy ra!)

$ python3        ## Run the Python interpreter
Python 3.X.X (XXX, XXX XX XXXX, XX:XX:XX) [XXX] on XXX
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 6       ## set a variable in this interpreter session
>>> a           ## entering an expression prints its value
6
>>> a + 2
8
>>> a = 'hi'    ## 'a' can hold a string just as well
>>> a
'hi'
>>> len(a)      ## call the len() function on a string
2
>>> a + len(a)  ## try something that doesn't work
Traceback (most recent call last):
  File "", line 1, in 
TypeError: can only concatenate str (not "int") to str
>>> a + str(len(a))  ## probably what you really wanted
'hi2'
>>> foo         ## try something else that doesn't work
Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'foo' is not defined
>>> ^D          ## type CTRL-d to exit (CTRL-z in Windows/DOS terminal)

Hai dòng mà python in sau khi bạn nhập python và trước dấu nhắc >>> cho biết phiên bản python mà bạn đang sử dụng và nơi phiên bản đó được tạo. Miễn là nội dung đầu tiên được in là "Python 3", các ví dụ này sẽ hoạt động cho bạn.

Như bạn có thể thấy ở trên, bạn có thể dễ dàng thử nghiệm các biến và toán tử. Ngoài ra, trình thông dịch sẽ gửi hoặc "tăng" (theo thuật ngữ Python) một lỗi thời gian chạy nếu mã cố gắng đọc một biến chưa được gán giá trị. Giống như C++ và Java, Python phân biệt chữ hoa chữ thường nên "a" và "A" là các biến khác nhau. Dấu kết thúc dòng đánh dấu dấu kết thúc câu lệnh, vì vậy, không giống như C++ và Java, Python không yêu cầu dấu chấm phẩy ở cuối mỗi câu lệnh. Nhận xét bắt đầu bằng dấu "#" và kéo dài đến cuối dòng.

Mã nguồn Python

Các tệp nguồn Python sử dụng đuôi ".py" và được gọi là "mô-đun". Với mô-đun Python hello.py, cách dễ nhất để chạy mô-đun này là dùng lệnh shell "python hello.py Alice". Lệnh này sẽ gọi trình thông dịch Python để thực thi mã trong hello.py, truyền cho mô-đun này đối số dòng lệnh "Alice". Hãy xem trang tài liệu chính thức để biết tất cả các lựa chọn khi chạy Python từ dòng lệnh.

Sau đây là một chương trình hello.py rất đơn giản (lưu ý rằng các khối mã được phân định nghiêm ngặt bằng cách thụt lề thay vì dấu ngoặc nhọn – chúng ta sẽ nói thêm về điều này sau!):

#!/usr/bin/python3

# import modules used here -- sys is a very standard one
import sys

# Gather our code in a main() function
def main():
    print('Hello there', sys.argv[1])
    # Command line args are in sys.argv[1], sys.argv[2] ...
    # sys.argv[0] is the script name itself and can be ignored

# Standard boilerplate to call the main() function to begin
# the program.
if __name__ == '__main__':
    main()

Khi chạy chương trình này từ dòng lệnh, bạn sẽ thấy:

$ python3 hello.py Guido
Hello there Guido
$ ./hello.py Alice  ## without needing 'python3' first (Unix)
Hello there Alice

Nhập, đối số dòng lệnh và len()

Các câu lệnh ngoài cùng trong một tệp Python hoặc "mô-đun" sẽ thực hiện quy trình thiết lập một lần – những câu lệnh đó chạy từ trên xuống dưới vào lần đầu tiên mô-đun được nhập ở đâu đó, thiết lập các biến và hàm của mô-đun. Bạn có thể chạy trực tiếp một mô-đun Python (như python3 hello.py Bob ở trên) hoặc có thể nhập và sử dụng mô-đun đó bằng một mô-đun khác. Khi một tệp Python được chạy trực tiếp, biến đặc biệt "__name__" sẽ được đặt thành "__main__". Do đó, bạn thường thấy đoạn mã if __name__ ==... ở trên để gọi một hàm main() khi mô-đun được chạy trực tiếp, nhưng không phải khi mô-đun được nhập bởi một số mô-đun khác.

Trong một chương trình Python tiêu chuẩn, danh sách sys.argv chứa các đối số dòng lệnh theo cách tiêu chuẩn, trong đó sys.argv[0] là chính chương trình, sys.argv[1] là đối số đầu tiên, v.v. Nếu biết về argv hoặc số lượng đối số, bạn chỉ cần yêu cầu giá trị này từ Python bằng len(sys.argv), giống như chúng ta đã làm trong mã trình thông dịch tương tác ở trên khi yêu cầu độ dài của một chuỗi. Nhìn chung, len() có thể cho bạn biết độ dài của một chuỗi, số lượng phần tử trong danh sách và bộ giá trị (một cấu trúc dữ liệu khác tương tự như mảng) cũng như số lượng cặp khoá-giá trị trong một từ điển.

Hàm do người dùng xác định

Các hàm trong Python được xác định như sau:

# Defines a "repeat" function that takes 2 arguments.
def repeat(s, exclaim):
    """
    Returns the string 's' repeated 3 times.
    If exclaim is true, add exclamation marks.
    """

    result = s + s + s # can also use "s * 3" which is faster (Why?)
    if exclaim:
        result = result + '!!!'
    return result

Cũng lưu ý cách các dòng tạo nên hàm hoặc câu lệnh if được nhóm lại bằng cách có cùng cấp độ thụt lề. Chúng tôi cũng trình bày 2 cách lặp lại chuỗi, sử dụng toán tử + thân thiện với người dùng hơn, nhưng * cũng hoạt động vì đây là toán tử "lặp lại" của Python, nghĩa là '-' * 10 cho ra '----------', một cách gọn gàng để tạo "đường kẻ" trên màn hình. Trong chú thích mã, chúng ta đã gợi ý rằng * hoạt động nhanh hơn + vì * tính toán kích thước của đối tượng kết quả một lần, trong khi với +, phép tính đó được thực hiện mỗi khi + được gọi. Cả + và * đều được gọi là toán tử "quá tải" vì chúng có ý nghĩa khác nhau đối với số so với chuỗi (và các kiểu dữ liệu khác).

Từ khoá def xác định hàm có các tham số trong dấu ngoặc đơn và mã được thụt lề. Dòng đầu tiên của một hàm có thể là một chuỗi tài liệu ("docstring") mô tả chức năng của hàm. Docstring có thể là một dòng hoặc nội dung mô tả nhiều dòng như trong ví dụ trên. (Đúng vậy, đó là "dấu ngoặc kép ba lần", một tính năng chỉ có ở Python!) Các biến được xác định trong hàm là cục bộ đối với hàm đó, vì vậy "result" trong hàm trên tách biệt với biến "result" trong một hàm khác. Câu lệnh return có thể nhận một đối số, trong trường hợp đó, đây là giá trị được trả về cho phương thức gọi.

Sau đây là mã gọi hàm repeat() ở trên, in những gì hàm này trả về:

def main():
    print(repeat('Yay', False))      ## YayYayYay
    print(repeat('Woo Hoo', True))   ## Woo HooWoo HooWoo Hoo!!!

Khi chạy, các hàm phải được xác định bằng cách thực thi "def" trước khi được gọi. Thông thường, bạn sẽ xác định một hàm main() ở cuối tệp cùng với các hàm mà hàm này gọi ở phía trên.

Thụt lề

Một tính năng bất thường của Python là khoảng trắng thụt lề của một đoạn mã sẽ ảnh hưởng đến ý nghĩa của đoạn mã đó. Một khối câu lệnh logic (chẳng hạn như những câu lệnh tạo nên một hàm) phải có cùng mức thụt lề, được đặt từ mức thụt lề của hàm mẹ hoặc "if" hoặc bất kỳ hàm nào khác. Nếu một trong các dòng trong một nhóm có thụt lề khác, thì dòng đó sẽ được gắn cờ là lỗi cú pháp.

Việc Python sử dụng khoảng trắng ban đầu có vẻ hơi lạ, nhưng nó rất hợp lý và tôi thấy mình đã quen với nó rất nhanh. Tránh sử dụng phím TAB vì phím này sẽ làm phức tạp đáng kể lược đồ thụt lề (chưa kể phím TAB có thể mang nhiều ý nghĩa trên các nền tảng khác nhau). Đặt trình chỉnh sửa để chèn dấu cách thay vì phím TAB cho mã Python.

Một câu hỏi thường gặp mà người mới bắt đầu hay hỏi là "Tôi nên thụt vào bao nhiêu khoảng trắng?" Theo hướng dẫn chính thức về kiểu Python (PEP 8), bạn nên thụt lề bằng 4 khoảng trắng. (Thông tin thú vị: Nguyên tắc về phong cách nội bộ của Google quy định thụt lề 2 dấu cách!)

Mã được kiểm tra trong thời gian chạy

Python kiểm tra rất ít tại thời điểm biên dịch, hoãn lại hầu hết các loại, tên, v.v. kiểm tra trên mỗi dòng cho đến khi dòng đó chạy. Giả sử main() ở trên gọi repeat() như sau:

def main():
    if name == 'Guido':
        print(repeeeet(name) + '!!!')
    else:
        print(repeat(name))

Câu lệnh if chứa một lỗi rõ ràng, trong đó hàm repeat() vô tình được nhập dưới dạng repeeeet(). Điều thú vị trong Python là mã này biên dịch và chạy tốt miễn là tên tại thời gian chạy không phải là "Guido". Chỉ khi một lần chạy thực sự cố gắng thực thi repeeeet(), nó mới nhận thấy không có hàm nào như vậy và phát sinh lỗi. Đoạn mã này cũng có lỗi thứ hai; tên chưa được gán giá trị trước khi so sánh với "Guido". Python sẽ đưa ra lỗi "NameError" nếu bạn cố gắng đánh giá một biến chưa được chỉ định. Đây là một số ví dụ minh hoạ rằng khi bạn chạy chương trình Python lần đầu tiên, một số lỗi đầu tiên mà bạn thấy sẽ là lỗi chính tả đơn giản hoặc các biến chưa được khởi tạo như thế này. Đây là một lĩnh vực mà các ngôn ngữ có hệ thống kiểu chi tiết hơn, chẳng hạn như Java, có lợi thế hơn ... chúng có thể phát hiện những lỗi như vậy tại thời điểm biên dịch (nhưng tất nhiên bạn phải duy trì tất cả thông tin về kiểu đó ... đó là một sự đánh đổi).

Python 3 giới thiệu gợi ý về kiểu. Gợi ý về kiểu cho phép bạn cho biết kiểu của từng đối số trong một hàm cũng như kiểu của đối tượng do hàm trả về. Ví dụ: trong hàm được chú thích def is_positive(n: int) -> bool:, đối số nint và giá trị trả về là bool. Chúng ta sẽ tìm hiểu ý nghĩa của các loại này ở phần sau. Tuy nhiên, bạn hoàn toàn không bắt buộc phải dùng gợi ý về kiểu. Bạn sẽ thấy ngày càng có nhiều mã áp dụng gợi ý về kiểu vì nếu bạn sử dụng các gợi ý này, một số trình chỉnh sửa như cider-v và VS.code có thể chạy các quy trình kiểm tra để xác minh rằng các hàm của bạn được gọi bằng các kiểu đối số phù hợp. Các công cụ này thậm chí có thể đề xuất và xác thực các đối số khi bạn chỉnh sửa mã. Hướng dẫn này sẽ không đề cập đến gợi ý về kiểu dữ liệu, nhưng chúng tôi muốn đảm bảo bạn biết về chúng nếu nghe nói hoặc thấy chúng ở đâu đó.

Tên biến

Vì các biến Python không có bất kỳ loại nào được nêu rõ trong mã nguồn, nên việc đặt tên có ý nghĩa cho các biến sẽ rất hữu ích để nhắc bạn về những gì đang diễn ra. Vì vậy, hãy sử dụng "name" nếu đó là một tên duy nhất, "names" nếu đó là một danh sách tên và "tuples" nếu đó là một danh sách các bộ. Nhiều lỗi cơ bản của Python là do bạn quên loại giá trị trong mỗi biến, vì vậy, hãy sử dụng tên biến (tất cả những gì bạn có) để giúp mọi thứ trở nên rõ ràng.

Về cách đặt tên thực tế, một số ngôn ngữ thích underscored_parts cho tên biến được tạo thành từ "nhiều từ", nhưng các ngôn ngữ khác lại thích camelCasing. Nhìn chung, Python ưu tiên phương thức dấu gạch dưới nhưng hướng dẫn các nhà phát triển tuân theo quy tắc viết hoa camelCase nếu tích hợp vào mã Python hiện có đã sử dụng kiểu đó. Tính dễ đọc rất quan trọng. Đọc thêm trong phần về quy ước đặt tên trong PEP 8.

Như bạn có thể đoán, bạn không thể dùng các từ khoá như "if" và "while" làm tên biến. Nếu làm vậy, bạn sẽ gặp lỗi cú pháp. Tuy nhiên, hãy cẩn thận để không dùng các hàm dựng sẵn làm tên biến. Ví dụ: mặc dù "str", "list" và "print" có vẻ là những tên hay, nhưng bạn sẽ ghi đè các biến hệ thống đó. Các hàm dựng sẵn không phải là từ khoá, do đó, các nhà phát triển Python mới có thể vô tình sử dụng chúng.

Thông tin khác về các mô-đun và vùng chứa tên của chúng

Giả sử bạn có một mô-đun "binky.py" chứa "def foo()". Tên đủ điều kiện của hàm foo đó là "binky.foo". Bằng cách này, nhiều mô-đun Python có thể đặt tên cho các hàm và biến theo ý muốn mà không bị xung đột tên biến – module1.foo khác với module2.foo. Trong từ vựng của Python, chúng ta có thể nói rằng binky, module1 và module2 đều có "không gian tên" riêng. Bạn có thể đoán rằng đây là các liên kết tên biến với đối tượng.

Ví dụ: chúng ta có mô-đun "sys" tiêu chuẩn chứa một số tiện ích hệ thống tiêu chuẩn, chẳng hạn như danh sách argv và hàm exit(). Với câu lệnh "import sys", sau đó bạn có thể truy cập vào các định nghĩa trong mô-đun sys và cung cấp các định nghĩa đó theo tên đủ điều kiện, ví dụ: sys.exit(). (Đúng vậy, "sys" cũng có một không gian tên!)

  import sys

  # Now can refer to sys.xxx facilities
  sys.exit(0)

Có một biểu mẫu nhập khác có dạng như sau: "from sys import argv, exit". Điều đó giúp argv và exit() có sẵn theo tên ngắn; tuy nhiên, bạn nên dùng dạng ban đầu với tên đủ điều kiện vì sẽ dễ dàng hơn nhiều khi xác định nguồn gốc của một hàm hoặc thuộc tính.

Có nhiều mô-đun và gói được đi kèm với một bản cài đặt tiêu chuẩn của trình thông dịch Python, nên bạn không cần làm gì thêm để sử dụng chúng. Những thư viện này được gọi chung là "Thư viện chuẩn Python". Các mô-đun/gói thường dùng bao gồm:

  • sys – quyền truy cập vào exit(), argv, stdin, stdout, ...
  • re – biểu thức chính quy
  • os – giao diện hệ điều hành, hệ thống tệp

Bạn có thể tìm thấy tài liệu của tất cả các mô-đun và gói Thư viện chuẩn tại http://docs.python.org/library.

Trợ giúp trực tuyến, help()dir()

Có nhiều cách để được trợ giúp về Python.

  • Tìm kiếm trên Google, bắt đầu bằng từ "python", chẳng hạn như "python list" (danh sách python) hoặc "python string lowercase" (chuỗi python viết thường). Kết quả đầu tiên thường là câu trả lời. Vì một số lý do, kỹ thuật này có vẻ hiệu quả hơn đối với Python so với các ngôn ngữ khác.
  • Trang tài liệu chính thức của Python – docs.python.org – có tài liệu chất lượng cao. Tuy nhiên, tôi thường thấy rằng việc tìm kiếm trên Google bằng một vài từ sẽ nhanh hơn.
  • Ngoài ra, còn có một danh sách gửi thư chính thức của Tutor được thiết kế dành riêng cho những người mới làm quen với Python và/hoặc lập trình!
  • Bạn có thể tìm thấy nhiều câu hỏi (và câu trả lời) trên StackOverflowQuora.
  • Sử dụng các hàm help() và dir() (xem bên dưới).

Bên trong trình thông dịch Python, hàm help() sẽ kéo các chuỗi tài liệu lên cho nhiều mô-đun, hàm và phương thức. Các chuỗi tài liệu này tương tự như javadoc của Java. Hàm dir() cho bạn biết các thuộc tính của một đối tượng. Dưới đây là một số cách gọi help() và dir() từ trình thông dịch:

  • help(len) – chuỗi trợ giúp cho hàm len() tích hợp; lưu ý rằng đó là "len" chứ không phải "len()", đây là một lệnh gọi đến hàm mà chúng ta không muốn
  • help(sys) – chuỗi trợ giúp cho mô-đun sys (trước tiên, bạn phải thực hiện import sys)
  • dir(sys)dir() tương tự như help() nhưng chỉ cung cấp danh sách nhanh các biểu tượng được xác định hoặc "thuộc tính"
  • help(sys.exit) – chuỗi trợ giúp cho hàm exit() trong mô-đun sys
  • help('xyz'.split) – chuỗi trợ giúp cho phương thức split() đối với các đối tượng chuỗi. Bạn có thể gọi help() bằng chính đối tượng đó hoặc ví dụ về đối tượng đó, cùng với thuộc tính của đối tượng. Ví dụ: gọi help('xyz'.split) cũng giống như gọi help(str.split).
  • help(list) – chuỗi trợ giúp cho các đối tượng list
  • dir(list) – hiển thị các thuộc tính đối tượng list, bao gồm cả các phương thức của đối tượng đó
  • help(list.append) – chuỗi trợ giúp cho phương thức append() của các đối tượng list