Hướng dẫn dùng 5 equals python
Nội dung chính Show
Cuốn sách Lập trình Python này được O2 Education sưu tầm và chia sẻ lại, chứ không phải tài liệu do chúng tôi viết. Lưu ý rằng phiên bản của cuốn sách này khá cũ, sử dụng Python 2.x nên có đôi chút khác biệt so với các phiên bản Python 3.x hiện nay. 0. Thông tin về bản quyềnBản quyền © 2001-2006 Python Software Foundation. Giữ toàn quyền. Bản quyền © 2000 BeOpen.com. Giữ toàn quyền. Bản quyền © 1995-2000 Corporation for National Research Initiatives. Giữ toàn quyền. Bản quyền © 1991-1995 Stichting Mathematisch Centrum. Giữ toàn quyền. Xem phần cuối của tài liệu này về toàn bộ thông tin quyền hạn và giấy phép. Tóm tắt:Python là một ngôn ngữ dễ học, và mạnh mẽ. Nó có những cấu trúc dữ liệu cấp cao hiệu quả và hướng lập trình đối tượng đơn giản. Cú pháp tao nhã và kiểu dữ liệu động của Python, cùng với bản chất thông dịch biến nó thành một ngôn ngữ bậc nhất để viết kịch bản (scripting) và phát triển ứng dụng nhanh trong nhiều lĩnh vực và trên hầu hết mọi hệ thống. Trình thông dịch Python và bộ thư viện chuẩn đầy đủ được cung cấp miễn phí ở dạng nguồn hoặc nhị phân cho mọi hệ thống chính từ trang chủ Python, http://www.python.org/, và có thể được phát tán tùy thích. Trang chủ đó cũng phân phối và liên kết nhiều mô-đun Python khác, các chương trình và công cụ, cũng như các tài liệu thêm. Trình thông dịch Python có thể được mở rộng dễ dàng với những chức năng và kiểu dữ liệu được viết trong C hoặc C++ (hoặc ngôn ngữ nào đó có thể gọi được từ C). Python cũng phù hợp dùng làm ngôn ngữ mở rộng cho các ứng dụng mà người dùng có thể cải biến. Bài chỉ dẫn này giới thiệu với người đọc bằng một cách dễ hiểu những khái niệm cơ bản và các tính năng của ngôn ngữ và hệ thống Python. Để tận dụng tốt nhất chỉ dẫn này, bạn nên có trình thông dịch Python sẵn sàng để thực tập. Nhưng bạn cũng không nhất thiết cần đến nó để đọc tài liệu này vì mọi ví dụ đều ngắn và dễ hiểu cả. Để tìm hiểu thêm về các mô-đun và đối tượng chuẩn, xem qua tài liệu Tham khảo thư viện Python. Sổ tay tham khảo Python chứa định nghĩa ngôn ngữ chính quy hơn. Để viết các phần mở rộng bằng C hoặc C++, bạn nên đọc Mở rộng và Nhúng trình thông dịch Python và Tham khảo API cho Python/C. Và cũng có nhiều sách khác nói sâu hơn về Python. Bài chỉ dẫn này không nhằm vào việc nói về mọi tính năng, hoặc thậm chí là mọi tính năng hay dùng. Thay vào đó, nó giới thiệu nhiều chức năng đáng lưu ý của Python và đem lại cho bạn một cách nhìn về kiểu cách và hương vị của ngôn ngữ này. Sau khi đọc xong, bạn sẽ có thể đọc và viết các mô-đun và chương trình Python, và bạn sẽ sẵn sàng tìm hiểu tiếp về những mô-đun Python khác được nhắc đến trong Tham khảo thư viện Python. Phiên bản 2.5, tài liệu được cập nhật ngày 19, tháng 09, năm 2006. 1. Khai vịNếu bạn làm việc nhiều với máy vi tính, một lúc nào đó bạn sẽ nhận thấy bạn muốn tự động hóa một số việc. Ví dụ, bạn muốn thực hiện một phép tìm kiếm và thay thế với nhiều tập tin văn bản, hoặc đổi tên và sắp xếp một loạt các tập tin ảnh theo một cách phức tạp. Có thể bạn muốn viết cơ sở dữ liệu tùy biến nho nhỏ, hoặc một ứng dụng với giao diện đồ họa đặc biệt, hay một trò chơi đơn giản. Nếu bạn là một người chuyên viết phần mềm, bạn có thể làm việc với nhiều thư viện C/C++/Java nhưng bạn nhận thấy thường lặp đi lặp lại việc viết/biên dịch/thử/biên dịch là quá tốn thời gian. Có thể bạn viết một bộ các thử nghiệm cho các thư viện ấy và nhận ra rằng viết mã lệnh để thử nghiệm là một việc chán ngấy. Hoặc có thể bạn viết một chương trình cần sử dụng một ngôn ngữ mở rộng, và bạn không muốn thiết kế, xây dựng cả một ngôn ngữ mới cho ứng dụng của mình. Python chính là ngôn ngữ lập trình bạn cần. Bạn có thể viết một kịch bản Unix hoặc một bó lệnh (batch file) Windows cho công việc kiểu này thế nhưng, ngôn ngữ kịch bản chỉ tốt cho việc chuyển các tập tin lòng vòng và sửa đổi các dữ liệu văn bản, nó không thích hợp cho một ứng dụng với giao diện đồ họa hoặc một trò chơi. Bạn cần viết một chương trình bằng C/C++/Java, nhưng nó có thể tiêu tốn nhiều thời gian cho việc phát triển thậm chí từ bản nháp đầu tiên của chương trình. Sử dụng Python đơn giản hơn, chạy được cả trên Windows, MacOS X, và các hệ điều hành Unix, và nó cũng giúp bạnh hoàn thành công việc nhanh hơn. Sử dụng ngôn ngữ lập trình Python thì đơn giản, nhưng nó là một ngôn ngữ lập trình thực thụ, cung cấp nhiều cấu trúc hơn và hỗ trợ các chương trình lớn hơn so với các ngôn ngữ kịch bản hoặc bó lệnh Windows. Mặt khác, Python cũng hỗ trợ nhiều phép kiểm tra lỗi hơn C, và, là một ngôn ngữ bậc-rất-cao, nó có sẵn các kiểu dữ liệu cấp cao, như các mảng và các từ điển linh hoạt. Chính vì nhiều kiểu dữ liệu tổng quát của nó Python được ứng dụng rộng rãi hơn Awk hoặc thậm chí là Perl trong nhiều loại công việc khác nhau, do đó có nhiều việc làm bằng Python cũng dễ dàng như làm bằng các ngôn ngữ khác. Ngôn ngữ lập trình Python cho phép bạn chia nhỏ chương trình của mình ra thành các mô-đun để có thể sử dụng lại trong các chương trình Python khác. Nó có sẵn rất nhiều các mô-đun chuẩn để bạn có thể sử dụng làm cơ sở cho chương trình của mình — hoặc như các ví dụ để bắt đầu học lập trình bằng Python. Một vài mô-đun trong số chúng cung cấp các chức năng như tập tin I/O (vào/ra), các lệnh gọi hàm hệ thống, các socket, và thậm chí các giao tiếp với các công cụ giao diện đồ họa như Tk. Python là một ngôn ngữ thông dịch, điều đó giúp bạn tiết kiệm thời gian trong quá trình phát triển chương trình vì việc biên dịch hay liên kết là không cần thiết. Bộ thông dịch có thể được dùng một cách tương tác, làm cho việc thử nghiệm các tính năng của ngôn ngữ trở nên dễ dàng, viết các chương trình bỏ đi, hoặc thử các chức năng trong việc phát triển chương trình từ dưới lên. Nó cũng là một máy tính cầm tay tiện lợi. Python cho phép viết các chương trình nhỏ gọn và dễ hiểu. Các chương trình viết bằng Python thường ngắn hơn so với các chương trình viết bằng C, C++ hoặc Java, vì nhiều lý do:
Python có tính mở rộng: nếu bạn biết lập trình C thì rất dễ để bổ sung các hàm có sẵn hoặc mô-đun vào bộ thông dịch, cũng như việc thực hiện các thao tác quan trọng ở tốc độ tối đa, hoặc liên kết các chương trình Python với các thư viện chỉ được cung cấp dưới dạng nhị phân (ví dụ như các thư viện đồ họa của một vài nhà sản xuất). Một khi bạn đã thực sự móc nối, bạn có thể liên kết bộ thông dịch Python vào trong các ứng dụng viết bằng C và sử dụng nó như một tính năng mở rộng hoặc một ngôn ngữ lệnh cho ứng dụng đó. Cũng xin nói luôn, tên của ngôn ngữ này được đặt sau khi BBC phát chương trình “Monty Python’s Flying Circus” và nó không có liên quan gì với những loài bò sát bẩn thỉu. Những tham khảo mang tính trào phùng tới Monty Python trong tài liệu không chỉ được cho phép, mà còn được cổ vũ. Bây giờ khi tất cả các bạn đã bị kích thích về Python, bạn sẽ muốn khám phá nó kỹ hơn. Cách học một ngôn ngữ tốt nhất là hãy sử dụng nó, bài chỉ dẫn này mời gọi bạn hãy vừa thử trình thông dịch Python khi bạn vừa đọc. Trong chương tiếp theo, các phương thức sử dụng bộ thông dịch sẽ được giải thích. Điều này không đơn thuần là thông tin, nhưng còn là cơ bản cho việc thử các ví dụ được trình bày về sau. Phần tự học còn lại sẽ giới thiệu các tính năng khác nhau của ngôn ngữ Python và hệ thống thông qua các ví dụ, bắt đầu với các biểu thức đơn giản, các câu lệnh và các kiểu dữ liệu, đi qua các hàm và các mô-đun, và kết thúc là tiếp cận với các khái niệm cao cấp như biệt lệ và các lớp do người dùng tự định nghĩa. 2. Sử dụng trình thông dịch Python2.1 Chạy trình thông dịchBộ thông dịch Python thường được cài đặt là /usr/local/bin/python trên các máy tính đã cài đặt sẵn; bổ sung /usr/local/bin vào đường dẫn tìm kiếm của vỏ (shell) Unix sẽ giúp khởi động nó từ mọi nơi bằng một lệnh đơn giản
trong shell. Vì nơi mà trình thông dịch được cài đặt là một tùy chọn nên khi cài đặt trình thông dịch có thể sẽ được đặt ở một nơi khác; hãy hỏi quản trị hệ thống của bạn. (ví dụ /usr/local/python cũng là một vị trí hay được dùng để cài.) Trên các máy tính dùng Windows, Python thường được cài đặt vào
Gõ một ký tự kết thúc tập tin (end-of-file character) (Control-D trên Unix, Control-Z trên Windows) tại dấu nhắc của bộ thông dịch sẽ thoát khỏi bộ thông dịch và trả về trạng thái kết thúc chương trình là Tính năng soạn thảo theo dòng của bộ thông dịch thường không phức tạp lắm. Trên Unix, bất cứ ai đã cài đặt bộ thông dịch đều có thể bật chế độ hỗ trợ cho thư viện GNU readline, điều này sẽ bổ sung tính năng soạn thảo tương tác tốt hơn cũng như các tính năng lịch sử lệnh. Có thể kiểm tra việc hỗ trợ tính năng soạn thảo dòng bằng cách nhấn Control-P tại dấu nhắc đầu tiên của Python. Nếu có tiếng bíp, bộ thông dịch của bạn có hỗ trợ soạn thảo dòng; xem phụ lục A để biết về các phím. Nếu không có gì xảy ra, hoặc kí tự P hiện lên, thì tính năng soạn thảo dòng không được hỗ trợ; bạn chỉ việc dùng phím lùi (backspace) để xóa kí tự hiện ra. Bộ thông dịch Python hoạt động khá giống với vỏ Unix: khi được gọi với một đầu nhập chuẩn đã kết nối với một thiết bị đầu cuối (tty device), nó đọc và thực hiện các lệnh một cách tương tác; khi được gọi với tham số là một tên tập tin hoặc với đầu vào chuẩn là một tập tin, nó đọc và thực hiện kịch bản chứa trong tập đó. Một cách nữa để khởi động bộ thông dịch là lệnh “ Một số mô-đun cũng có thể được dùng như kịch bản. Chúng có thể được gọi bằng cách sử dụng cú pháp “ Xin lưu ý rằng có
sự khác biệt giữa “ Khi tập tin kịch bản (script file) được sử dụng, đôi khi sẽ rất hữu dụng nếu có thể chạy chương trình và chuyển sang chế độ tương tác ngay sau đó. Điều này thực hiện được bằng cách truyền 2.1.1 Truyền tham sốBộ thông dịch nhận biết tên chương trình và các tham số
khác được truyền vào chương trình trong biến 2.1.2 Chế độ tương tácKhi các lệnh được đọc từ một tty, trình thông dịch được xem là đang trong chế độ tương tác. Trong chế độ này nó nhắc lệnh tiếp theo với dấu nhắc chính (primary prompt), thường là ba dấu lớn hơn python Python 1.5.2b2 (#1, Feb 28 1999, 00:02:06) [GCC 2.8.1] on sunos5 Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam >>> Các dòng nối tiếp được dùng khi nhập vào các cấu trúc nhiều dòng. Hãy xem ví dụ dưới, chú ý câu lệnh if : >>> the_world_is_flat = 1 >>> if the_world_is_flat: ... print "Be careful not to fall off!" ... Be careful not to fall off! 2.2 Trình thông dịch và môi trường của nó2.2.1 Xử lý lỗiKhi xảy ra một lỗi, bộ dịch in ra thông báo lỗi và lần ngược ngăn xếp (stack trace). Trong chế độ tương tác, nó sẽ trả lại dấu nhắc chính; khi đầu vào là một tập tin, nó sẽ thoát với mã lỗi khác 0 sau khi in ra lần ngược ngăn xếp. (Các biệt lệ được xử lý bởi vế except trong một câu lệnh try không phải là các lỗi chúng ta nói đến ở đây.) Một số lỗi là nghiêm trọng không điều kiện và gây ra lỗi thoát với giá trị lỗi khác 0; điều này áp dụng cho các trường hợp mâu thuẫn nội tại và một vài trường hợp tràn bộ nhớ. Tất cả các thông báo lỗi đều được xuất ra dòng xuất lỗi chuẩn (standard error stream); kết xuất bình thường sẽ được xuất ra dòng xuất chuẩn (standard output – xin được hiểu là màn hình, tập tin…). Gõ kí tự ngắt (thường là Control-C hoặc DEL) vào dấu nhắc chính hoặc dấu nhắc thứ sẽ bỏ những gì đã nhập vào và trở về dấu nhắc chính[1].Gõ kí tự ngắt trong khi một lệnh đang được thực thi sẽ gây ra biệt lệ KeyboardInterrupt, trường hợp này có thể được xử lý bằng câu lệnh try. 2.2.2 Các kịch bản Python khả thiTrên các hệ thống Unix họ BSD, các kịch bản Python có thể được thực thi trực tiếp, như các kịch bản vỏ (shell script), bằng cách thêm dòng
(giả sử rằng bộ thông dịch đã có trong PATH của người dùng) ở đầu kịch bản và đặc thuộc tính thực thi (executable mode) cho tập tin đó. Ký hiệu “ Kịch bản có thể được đặt quyền thực thi bằng cách dùng lệnh chmod :
2.2.3 Bảng mã mã nguồnCó thể sử dụng các bảng mã khác bảng ASCII trong các tập tin nguồn Python. Cách tốt nhất là thêm các dòng chú thích đặc biệt vào ngay sau dòng #! để định nghĩa bảng mã trong tập tin:
Với khai báo này, mọi ký tự trong tập tin nguồn sẽ được xem như từ bảng mã encoding, và vì vậy ta có thể viết các chuỗi Unicode trực tiếp trong bảng mã đó. Danh sách các bảng mã có thể được tìm thấy ở Tham khảo thư viện Python, trong phần codecs. Ví dụ, để viết ký tự biểu diễn đồng Euro, ta có thể sử dụng bảng mã ISO-8859-15, kí hiệu Euro có số thứ tự 164 trong bảng mã. Đoạn chương trình sau sẽ in ra giá trị 8364 (mã Unicode tương ứng với kí tự biểu diễn Euro) và thoát: # -*- coding: iso-8859-15 -*- currency = u"€" print ord(currency) Nếu bộ soạn thảo của bạn hỗ trợ lưu tập tin theo UTF-8 với đánh dấu thứ tự byte UTF-8 (UTF-8 byte order mark – BOM), bạn có thể dùng nó thay thế cho một khai báo bảng mã. IDLE hỗ trợ sự tương thích này nếu Options/General/Default Source Encoding/UTF-8 được thiết lập. Chú ý rằng ký hiệu này không được các phiên bản Python 2.2 trở về trước nhận biết, và cũng không được hệ điều hành nhận biết là các tập tin kịch bản với các dòng #! (chỉ được dùng trên các hệ Unix ). Với việc sử dụng UTF-8 (thông qua kí hiệu cũng như khai báo bảng mã), các kí tự trong hầu hết các ngôn ngữ trên thế giới có thể được sử dụng đồng thời trong các chuỗi nguyên bản và các chú thích. Sử dụng các kí tự phi chuẩn ASCII trong các định danh thì không được hỗ trợ. Để hiển thị đúng các kí tự, bộ soạn thảo của bạn nhất thiết phải nhận biết tập tin UTF-8 và buộc phải sử dụng các phông chữ hỗ trợ tốt các kí tự này. 2.2.4 Tập tin khởi tạo tương tácKhi bạn sử dụng Python ở chế độ tương tác, sẽ rất tiện lợi khi có một số lệnh chuẩn luôn được thực hiện mỗi khi bộ thông dịch khởi động. Bạn có thể thực hiện việc này bằng cách thiết lập một biến môi trường có tên PYTHONSTARTUP với giá trị là tên của tập tin bạn chứa các câu lệnh khởi tạo. Cách này tương tự như chức năng.profile của vỏ Unix. Tập tin này chỉ được đọc trong phiên làm việc tương tác, không có tác dụng với các kịch bản, và khi /dev/tty được chỉ định rõ là nguồn lệnh (nếu không thì trường hợp này cũng giống như một phiên làm việc tương tác). Nó được thực thi trong cùng vùng tên (namespace) mà các lệnh tương tác được thực thi, cho nên các đối tượng nó định nghĩa, hoặc nhập vào (import) có thể được dùng mà không cần xác nhận trong phiên làm việc tương tác. Bạn cũng có thể thay đổi dấu nhắc sys.ps1 và sys.ps2 trong tập tin này. Nếu bạn muốn đọc các tập khởi động bổ sung từ thư mục hiện tại, bạn có thể lập trình điều này trong tập tin khởi động với mã như “if os.path.isfile(‘.pythonrc.py’): execfile(‘.pythonrc.py’)”. Nếu bạn muốn dùng tập tin khởi động trong một kịch bản, bạn phải chỉ rõ điều này trong kịch bản: import os filename = os.environ.get('PYTHONSTARTUP') if filename and os.path.isfile(filename): execfile(filename) 3. Giới thiệu sơ lược về ngôn ngữ lập trình PythonTrong 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 (“ 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ínhHã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, “ 3.1.1 Kiểu số trong ngôn ngữ lập trình PythonTrì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ử >>> 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 (“ >>> 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ố “ >>> 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 >>> 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 ( >>> a=3.0+4.0j >>> float(a) Traceback (most recent call last): File " Trong chế độ tương tác, biểu thức được in ra cuối cùng được gán vào biến >>> 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ỗiNgoà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 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 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: 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.) >>> word = 'Help' + 'A' >>> word 'HelpA' >>> '<' + word*5 + '>' ' 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 “ >>> 'str' 'ing' # <- This is ok 'string' >>> 'str'.strip() + 'ing' # <- This is ok 'string' >>> 'str'.strip() 'ing' # <- This is invalid File " 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 >>> 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 " 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: >>> 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 >>> 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 " 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 >>> s = 'supercalifragilisticexpialidocious' >>> len(s) 34 Xem thêm:
3.1.3 Chuỗi UnicodeBắ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. >>> u'Hello World !' u'Hello World !' Ký tự “ >>> u'Hello\u0020World !' u'Hello World !' Dãy thoát
nghĩa >>> 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). >>> u"abc" u'abc' >>> str(u"abc") 'abc' >>> u"äöü" u'\xe4\xf6\xfc' >>> str(u"äöü") Traceback (most recent call last): File " Để 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 >>> 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('\xc3\xa4\xc3\xb6\xc3\xbc', 'utf-8') u'\xe4\xf6\xfc' 3.1.4 Danh sáchPython 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ừ >>> 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(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] và 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ìnhDĩ 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.
>>> i = 256*256 >>> print 'The value of i is', i The value of i is 65536 Dấu phẩy sau cùng tránh dòng mới sau khi xuất: >>> a, b = 0, 1 >>> while b < 1000: ... print b, ... a, b = b, a+b ... 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 Lưu ý rằng trình thông dịch chèn một dòng mới trước khi nó in ra dấu nhắc kế nếu dòng trước chưa xong. 4. Bàn thêm về luồng điều khiểnNgoài câu lệnh while vừa giới thiệu, Python có các câu lệnh điều khiển luồng từ các ngôn ngữ khác, với chút sửa đổi. 4.1 Câu lệnh điều kiện if trong ngôn ngữ lập trình PythonCó lẽ loại câu lệnh biết đến nhiều nhất là câu lệnh >>> x = int(raw_input("Please enter an integer: ")) >>> if x < 0: ... x = 0 ... print 'Negative changed to zero' ... elif x == 0: ... print 'Zero' ... elif x == 1: ... print 'Single' ... else: ... print 'More' ... Có thể không có hoặc có nhiều phần 4.2 Câu lệnh vòng lặp for trong lập trình PythonVòng lặp
>>> # Measure some strings: ... a = ['cat', 'window', 'defenestrate'] >>> for x in a: ... print x, len(x) ... cat 3 window 6 defenestrate 12 Rất nguy hiểm nếu bạn sửa đổi dãy trong khi bạn đang lặp qua nó. Nếu bạn cần sửa đổi một danh sách khi đang lặp (ví dụ như để nhân đôi các phần tử nào đó) bạn sẽ cần phải lặp qua một bản sao của nó. Cách viết cắt miếng làm cho việc này đơn giản: >>> for x in a[:]: # make a slice copy of the entire list ... if len(x) > 6: a.insert(0, x) ... >>> a ['defenestrate', 'cat', 'window', 'defenestrate'] 4.3 Hàm range() trong lập trình PythonNếu bạn cần lặp qua một dãy số, hàm có sẵn >>> range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] Điểm dừng được chỉ định không bao giờ là một phần của danh sách tạo ra; >>> range(5, 10) [5, 6, 7, 8, 9] >>> range(0, 10, 3) [0, 3, 6, 9] >>> range(-10, -100, -30) [-10, -40, -70] Để lặp qua các chỉ mục của một dãy, gộp >>> a = ['Mary', 'had', 'a', 'little', 'lamb'] >>> for i in range(len(a)): ... print i, a[i] ... 0 Mary 1 had 2 a 3 little 4 lamb 4.4 Câu lệnh break và continue, mệnh đề else cho vòng lặpCâu lệnh Câu lệnh Các câu lệnh lặp có thể có vế >>> for n in range(2, 10): ... for x in range(2, n): ... if n % x == 0: ... print n, 'equals', x, '*', n/x ... break ... else: ... # loop fell through without finding a factor ... print n, 'is a prime number' ... 2 is a prime number 3 is a prime number 4 equals 2 * 2 5 is a prime number 6 equals 2 * 3 7 is a prime number 8 equals 2 * 4 9 equals 3 * 3 4.5 Câu lệnh pass
>>> while True: ... pass # Busy-wait for keyboard interrupt ... 4.6 Định nghĩa hàm trong lập trình PythonChúng ta có thể tạo một hàm in ra dãy Fibonacci: >>> def fib(n): # write Fibonacci series up to n ... """Print a Fibonacci series up to n.""" ... a, b = 0, 1 ... while b < n: ... print b, ... a, b = b, a+b ... >>> # Now call the function we just defined: ... fib(2000) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 Từ khóa Có những công cụ sử dụng docstrings để tự động sinh tài liệu trực tuyến hoặc để in, hoặc cho phép người dùng duyệt mã một cách tương tác; việc thêm docstrings vào mã rất được khuyến khích, cho nên bạn hãy tạo thói quen tốt đó cho mình. Việc thực thi một hàm tạo ra một bảng ký hiệu mới dùng cho các biến cục bộ của hàm. Chính xác hơn, mọi phép gán biến trong một hàm chứa giá trị vào bảng ký hiệu cục bộ; và các tham chiếu biến sẽ trước hết tìm trong bảng ký hiệu cục bộ rồi trong bảng ký hiệu toàn cục, và trong bảng các tên có sẵn. Do đó, các biến toàn cục không thể được gán giá trị trực tiếp trong một hàm (trừ khi được đặt trong câu lệnh global ), mặc dù chúng có thể dược tham chiếu tới. Thông số thật sự của một lệnh gọi hàm được tạo ra trong bảng ký hiệu cục bộ của hàm được gọi khi nó được gọi; do đó các thông số được truyền theo truyền theo giá trị (call by value) (mà giá trị luôn là một tham chiếu đối tượng, không phải là giá trị của đối tượng[2]). Khi một hàm gọi một hàm khác, một bảng ký hiệu cục bộ được tạo ra cho lệnh gọi đó. Một định nghĩa hàm tạo tên hàm trong bảng ký hiệu hiện tại. Giá trị của tên hàm có một kiểu được nhận ra bởi trình thông dịch là hàm do người dùng định nghĩa. Giá trị này có thể được gán vào một tên khác và sau đó có thể được sử dụng như một hàm. Đây là một cách đổi tên tổng quát: >>> fib Bạn có thể nói rằng fib không phải là một hàm (function) mà là một thủ tục (procedure). Trong Python, cũng như C, thủ tục chẳng qua là hàm không có giá trị trả về. Thật sự, nói rõ hơn một chút, thủ tục cũng trả về giá trị mặc dù là một giá trị vô nghĩa. Giá trị này được gọi là None (nó là một tên có sẵn). In ra giá trị None thường bị trình thông dịch bỏ qua nếu nó là giá trị duy nhất được in ra. Bạn có thể thấy nó nếu bạn muốn: >>> print fib(0) None Bạn cũng có thể dễ dàng viết một hàm trả về một danh sách các số của dãy Fibonacci thay vì in nó ra: >>> def fib2(n): # return Fibonacci series up to n ... """Return a list containing the Fibonacci series up to n.""" ... result = [] ... a, b = 0, 1 ... while b < n: ... result.append(b) # see below ... a, b = b, a+b ... return result ... >>> f100 = fib2(100) # call it >>> f100 # write the result [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] Ví dụ này cho thấy một vài tính năng mới của ngôn ngữ lập trình Python:
4.7 Bàn thêm về định nghĩa hàmBạn cũng có thể định nghĩa các hàm với số lượng thông số thay đổi. Có ba dạng, và chúng có thể được dùng chung với nhau. 4.7.1 Giá trị thông số mặc địnhDạng hữu dụng nhất là để chỉ định một giá trị mặc định cho một hoặc nhiều thông số. Dạng này tạo một hàm có thể được gọi với ít thông số hơn là nó được định nghĩa để nhận. Ví dụ: def ask_ok(prompt, retries=4, complaint='Yes or no, please!'): while True: ok = raw_input(prompt) if ok in ('y', 'ye', 'yes'): return True if ok in ('n', 'no', 'nop', 'nope'): return False retries = retries - 1 if retries < 0: raise IOError, 'refusenik user' print complaint Hàm này có thể được gọi như sau: Ví dụ này giới thiệu từ khóa Các giá trị mặc định được định giá tại nơi hàm được định nghĩa trong phạm vi định nghĩa (defining scope), do đó i = 5 def f(arg=i): print arg i = 6 f() sẽ in 5 của hàm. def f(a, L=[]): L.append(a) return L print f(1) print f(2) print f(3) Sẽ in ra [1] [1, 2] [1, 2, 3] Nếu bạn không muốn mặc định được dùng chung trong các lời gọi sau, bạn có thể viết một hàm như thế này: def f(a, L=None): if L is None: L = [] L.append(a) return L 4.7.2 Thông số từ khóaCác hàm cũng có thể được gọi theo thông số từ khóa (keyword argument) theo dạng “ def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'): print "-- This parrot wouldn't", action, print "if you put", voltage, "volts through it." print "-- Lovely plumage, the", type print "-- It's", state, "!" có thể được gọi theo bất kỳ cách nào: parrot(1000) parrot(action = 'VOOOOOM', voltage = 1000000) parrot('a thousand', state = 'pushing up the daisies') parrot('a million', 'bereft of life', 'jump') nhưng những lời gọi sau đều không hợp lệ: parrot() # required argument missing parrot(voltage=5.0, 'dead') # non-keyword argument following keyword parrot(110, voltage=220) # duplicate value for argument parrot(actor='John Cleese') # unknown keyword Nói chung, một danh sách thông số phải có bất kỳ thông số vị trí (positional argument) theo sau bởi bất kỳ thông số từ khóa, các từ khóa phải được chọn từ tên thông số chính quy. Các thông số chính quy không nhất thiết phải có giá trị mặc định. Không thông số nào có thể nhận một giá trị nhiều hơn một lần — tên thông số chính quy tương ứng với thông số vị trí không thể được dùng làm từ khóa trong cùng một lời gọi. Sau đây là một ví dụ sai vì giới hạn này: >>> def function(a): ... pass ... >>> function(0, a=0) Traceback (most recent call last): File " Khi thông số chính quy cuối có dạng def cheeseshop(kind, *arguments, **keywords): print "-- Do you have any", kind, '?' print "-- I'm sorry, we're all out of", kind for arg in arguments: print arg print '-'*40 keys = keywords.keys() keys.sort() for kw in keys: print kw, ':', keywords[kw] Nó có thể được gọi như vậy: cheeseshop('Limburger', "It's very runny, sir.", "It's really very, VERY runny, sir.", client='John Cleese', shopkeeper='Michael Palin', sketch='Cheese Shop Sketch') và dĩ nhiên nó sẽ in ra: -- Do you have any Limburger ? -- I'm sorry, we're all out of Limburger It's very runny, sir. It's really very, VERY runny, sir. ---------------------------------------- client : John Cleese shopkeeper : Michael Palin sketch : Cheese Shop Sketch Lưu ý rằng phương thức 4.7.3 Danh sách thông số bất kỳCuối cùng, một lựa chọn ít dùng nhất để chỉ định rằng một hàm có thể được gọi với bất kỳ số thông số. Các thông số này sẽ được gói và trong một bộ. Trước các thông số không xác định, không hoặc nhiều hơn các thông số chính quy có thể có mặt. def fprintf(file, format, *args): file.write(format % args) 4.7.4 Tháo danh sách thông sốTrường hợp ngược xảy ra khi các thông số đã nằm trong một danh sách hoặc một bộ nhưng cần được tháo ra cho lời gọi hàm
cần những thông số vị trí riêng. Ví dụ, hàm có sẵn >>> range(3, 6) # normal call with separate arguments [3, 4, 5] >>> args = [3, 6] >>> range(*args) # call with arguments unpacked from a list [3, 4, 5] Theo cùng một kiểu, từ điển có thể cung cấp các thông số từ khóa với toán tử >>> def parrot(voltage, state='a stiff', action='voom'): ... print "-- This parrot wouldn't", action, ... print "if you put", voltage, "volts through it.", ... print "E's", state, "!" ... >>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"} >>> parrot(**d) -- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised ! 4.7.5 Hàm nặc danh dạng lambdaTheo yêu cầu chung, một vài tính năng thường thấy trong các ngôn ngữ lập trình hàm như Lisp đã được thêm vào
Python. Với từ khóa lambda, các hàm vô danh (anonymous function) có thể được tạo ra. Đây là một hàm trả vè tổng của hai thông số: “ >>> def make_incrementor(n): ... return lambda x: x + n ... >>> f = make_incrementor(42) >>> f(0) 42 >>> f(1) 43 4.7.6 Chuỗi tài liệuCó những quy luật đang hình thành về nội dung và định dạng của các chuỗi tài liệu. Dòng đầu tiên cần phải luôn luôn là một tóm tắt ngắn, xúc tích về mục đích của đối tượng. Để dễ hiểu, nó không nên chỉ ra cụ thể tên hoặc kiểu của đối tượng vì chúng có thể có ở hình thức khác (từ khi tên là một động từ diễn tả hoạt động của hàm). Dòng này cần bắt đầu bằng một chữ hoa và kết thúc bằng một dấu chấm. Nếu có nhiều dòng trong chuỗi tài liệu, dòng thứ hai nên là một dòng trống, rõ ràng phân biệt tóm tắt và phần còn lại. Các dòng sau nên là một hoặc nhiều đoạn hướng dẫn về cách gọi, các hiệu ứng phụ, v.v… Bộ phân tích ngữ pháp Python không lọc thụt hàng từ các chuỗi đa dòng (multi-line string literal) trong Python, so nên các công cụ xử lý tài liệu cần phải lọc thụt hàng nếu cần. Việc này được làm theo một cách chung. Dòng không trống đầu tiên sau dòng đầu tiên của chuỗi xác định mức thụt vào cho toàn bộ chuỗi tài liệu. (Ta không thể dùng dòng đầu tiên vì nó thường nằm kế dấu nháy đầu chuỗi cho nên mức thụt vào của nó không được xác định trong cách viết chuỗi.) Khoảng trắng “tương đương” với mức thụt vào này được bò khỏi mỗi đầu dòng trong chuỗi. Không nên có các dòng thụt vào ít hơn, nhưng nếu gặp phải, toàn bộ khoảng trắng đầu của chúng nên được bỏ đi. Tính tương đương của khoảng trắng cần được kiểm tra sau khi mở rộng tab (thông thường thành 8 khoảng trắng). Đâu là ví dụ của một docstring đa dòng: >>> def my_function(): ... """Do nothing, but document it. ... ... No, really, it doesn't do anything. ... """ ... pass ... >>> print my_function.__doc__ Do nothing, but document it. No, really, it doesn't do anything. 5. Cấu trúc dữ liệu trong ngôn ngữ lập trình PythonChương này diễn giải kỹ hơn một vài điều bạn đã học được, và cũng nói thêm về một số điều mới. 5.1 Bàn thêm về danh sáchKiểu dữ liệu danh sách (kiểu
Một ví dụ có sử dụng hầu hết các phương thức của danh sách: >>> a = [66.25, 333, 333, 1, 1234.5] >>> print a.count(333), a.count(66.25), a.count('x') 2 1 0 >>> a.insert(2, -1) >>> a.append(333) >>> a [66.25, 333, -1, 333, 1, 1234.5, 333] >>> a.index(333) 1 >>> a.remove(333) >>> a [66.25, -1, 333, 1, 1234.5, 333] >>> a.reverse() >>> a [333, 1234.5, 1, 333, -1, 66.25] >>> a.sort() >>> a [-1, 1, 66.25, 333, 333, 1234.5] 5.1.1 Dùng danh sách như ngăn xếpCác phương thức của danh sách làm cho nó rất dễ sử dụng như là ngăn xếp (stack), là nơi mà phần tử cuối được thêm vào là phần tử đầu được lấy ra (“vào sau, ra trước” hay “last-in, first-out”). Để thêm phần tử vào đỉnh của ngăn xếp, dùng >>> stack = [3, 4, 5] >>> stack.append(6) >>> stack.append(7) >>> stack [3, 4, 5, 6, 7] >>> stack.pop() 7 >>> stack [3, 4, 5, 6] >>> stack.pop() 6 >>> stack.pop() 5 >>> stack [3, 4] 5.1.2 Dùng danh sách như hàng đợiBạn cũng có thể thuận tiện dùng danh sách như là hàng đợi (queue), nơi mà phần tử được thêm vào đầu tiên là phần tử được lấy ra đầu tiên (“vào trước, ra trước” hay “first-in, first-out”). Để thêm một phần tử vào cuối hàng đợi, dùng >>> queue = ["Eric", "John", "Michael"] >>> queue.append("Terry") # Terry arrives >>> queue.append("Graham") # Graham arrives >>> queue.pop(0) 'Eric' >>> queue.pop(0) 'John' >>> queue ['Michael', 'Terry', 'Graham'] 5.1.3 Công cụ lập trình hướng hàmCó sẵn ba hàm rất hữu dụng khi dùng với danh
sách:
>>> def f(x): return x % 2 != 0 and x % 3 != 0 ... >>> filter(f, range(2, 25)) [5, 7, 11, 13, 17, 19, 23]
>>> def cube(x): return x*x*x ... >>> map(cube, range(1, 11)) [1, 8, 27, 64, 125, 216, 343, 512, 729, 1000] Có thể truyền vào nhiều dãy; hàm đó phải nhận từng
ấy thông số với mỗi phần tử trong mỗi dãy là một thông số (hoặc >>> seq = range(8) >>> def add(x, y): return x+y ... >>> map(add, seq, seq) [0, 2, 4, 6, 8, 10, 12, 14]
>>> def add(x,y): return x+y ... >>> reduce(add, range(1, 11)) 55 Nếu chỉ có một phần tử trong dãy, giá trị của nó sẽ được trả về; nếu dãy rỗng, ngoại lệ sẽ xuất hiện. Có thể truyền thêm thông số thứ ba để cho biết giá trị ban đầu. Trong trường hợp đó, giá trị này sẽ được trả về nếu dãy rỗng, và hàm sẽ được áp dụng cho giá trị ban đầu, và giá trị của phần tử đầu của dãy, rồi với giá trị được trả về với giá trị của phần tử kế, và cứ thế. Ví dụ, >>> def sum(seq): ... def add(x,y): return x+y ... return reduce(add, seq, 0) ... >>> sum(range(1, 11)) 55 >>> sum([]) 0 Đừng dùng định nghĩa của ví dụ này về 5.1.4 Gộp danh sáchViệc gộp danh
sách (list comprehension) cung cấp một cách xúc tích để tạo danh sách mà không cần dùng tới >>> freshfruit = [' banana', ' loganberry ', 'passion fruit '] >>> [weapon.strip() for weapon in freshfruit] ['banana', 'loganberry', 'passion fruit'] >>> vec = [2, 4, 6] >>> [3*x for x in vec] [6, 12, 18] >>> [3*x for x in vec if x > 3] [12, 18] >>> [3*x for x in vec if x < 2] [] >>> [[x,x**2] for x in vec] [[2, 4], [4, 16], [6, 36]] >>> [x, x**2 for x in vec] # error - parens required for tuples File " Cách gộp danh sách uyển chuyển hơn nhiều so với >>> [str(round(355/113.0, i)) for i in range(1,6)] ['3.1', '3.14', '3.142', '3.1416', '3.14159'] 5.2 Câu lệnh delCó một cách để bỏ một phần tử ra khỏi danh sách dựa trên chỉ mục của nó, thay vì giá trị: câu lệnh >>> a = [-1, 1, 66.25, 333, 333, 1234.5] >>> del a[0] >>> a [1, 66.25, 333, 333, 1234.5] >>> del a[2:4] >>> a [1, 66.25, 1234.5] >>> del a[:] >>> a []
>>> del a Tham chiếu tới tên 5.3 Bộ và dãyChúng ta đã thấy rằng danh sách và chuỗi có nhiều thuộc tính chung, như là có chỉ mục, và các toán
tử cắt miếng. Chúng là hai ví dụ của dãy (sequence) kiểu dữ liệu. Vì Python là một ngôn ngữ đang phát triển, các kiểu dữ liệu dãy khác có thể được thêm vào. Có một kiểu dãy chuẩn khác: bộ Một >>> t = 12345, 54321, 'hello!' >>> t[0] 12345 >>> t (12345, 54321, 'hello!') >>> # Tuples may be nested: ... u = t, (1, 2, 3, 4, 5) >>> u ((12345, 54321, 'hello!'), (1, 2, 3, 4, 5)) Khi xuất ra, Vấn đề đặc biệt là trong việc tạo nên >>> empty = () >>> singleton = 'hello', # <-- note trailing comma >>> len(empty) 0 >>> len(singleton) 1 >>> singleton ('hello',) Câu lệnh >>> x, y, z = t Và nó được gọi là tháo dãy.
Việc tháo dãy yêu cầu danh sách các biến bên trái có cùng số phần tử như độ lớn của dãy. Chú ý rằng phép đa gán (multiple assignment) thật ra chỉ là sự tổng hợp của việc gói Có một điểm không đối xứng ở đây: việc gói nhiều giá trị luôn luôn tạo một 5.4 Tập hợpPython cũng có một kiểu dữ liệu cho tập hợp ( Đây là một ví dụ ngắn: >>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana'] >>> fruit = set(basket) # create a set without duplicates >>> fruit set(['orange', 'pear', 'apple', 'banana']) >>> 'orange' in fruit # fast membership testing True >>> 'crabgrass' in fruit False >>> # Demonstrate set operations on unique letters from two words ... >>> a = set('abracadabra') >>> b = set('alacazam') >>> a # unique letters in a set(['a', 'r', 'b', 'c', 'd']) >>> a - b # letters in a but not in b set(['r', 'd', 'b']) >>> a | b # letters in either a or b set(['a', 'c', 'r', 'd', 'b', 'm', 'z', 'l']) >>> a & b # letters in both a and b set(['a', 'c']) >>> a ^ b # letters in a or b but not both set(['r', 'd', 'b', 'm', 'z', 'l']) 5.5 Từ điểnMột kiểu dữ liệu hữu dụng khác được đưa vào Python là từ điển (dictionary). Từ điển được tìm thấy trong các ngôn ngữ khác như “bộ nhớ kết hợp (associative memory)” hoặc “mảng kết hợp (associative array)”. Không như dãy được chia chỉ mục từ một
khoảng số, từ điển được chia chỉ mục từ các khóa, có thể là bất kỳ kiểu không đổi nào; chuỗi và số luôn luôn có thể làm khóa. Dễ nhất là nghĩ về
từ điển như một tập hợp không thứ tự của các bộ khóa: giá trị, với điều kiện là khóa phải là duy nhất (trong cùng một từ điển). Một cặp ngoặc nhọn tạo một từ điển rỗng: Công việc chính của từ điển là chứa một giá trị vào một khóa nào đó và lấy lại giá trị từ khóa đó. Cũng có thể xóa một cặp Phương thức Đây là một ví dụ nhỏ về cách dùng từ điển: >>> tel = {'jack': 4098, 'sape': 4139} >>> tel['guido'] = 4127 >>> tel {'sape': 4139, 'guido': 4127, 'jack': 4098} >>> tel['jack'] 4098 >>> del tel['sape'] >>> tel['irv'] = 4127 >>> tel {'guido': 4127, 'irv': 4127, 'jack': 4098} >>> tel.keys() ['guido', 'irv', 'jack'] >>> tel.has_key('guido') True >>> 'guido' in tel True Phương thức >>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)]) {'sape': 4139, 'jack': 4098, 'guido': 4127} >>> dict([(x, x**2) for x in (2, 4, 6)]) # use a list comprehension {2: 4, 4: 16, 6: 36} Ở phần sau của bài chỉ dẫn chúng ta sẽ tìm hiểu về các biểu thức bộ tạo thích hợp hơn với việc cung cấp các cặp khóa-giá trị vào hàm khởi tạo >>> dict(sape=4139, guido=4127, jack=4098) {'sape': 4139, 'jack': 4098, 'guido': 4127} 5.6 Kỹ thuật lặpKhi lặp qua từ điển, khóa và giá trị tương ứng có thể được lấy ra cùng lúc bằng phương thức >>> knights = {'gallahad': 'the pure', 'robin': 'the brave'} >>> for k, v in knights.iteritems(): ... print k, v ... gallahad the pure robin the brave Khi lặp qua một dãy, vị trí chỉ mục và giá trị tương ứng có thể được lấy ra cùng lúc bằng hàm >>> for i, v in enumerate(['tic', 'tac', 'toe']): ... print i, v ... 0 tic 1 tac 2 toe Để lặp qua hai hoặc nhiều dãy cùng lúc, các phần tử có thể được ghép với nhau bằng hàm >>> questions = ['name', 'quest', 'favorite color'] >>> answers = ['lancelot', 'the holy grail', 'blue'] >>> for q, a in zip(questions, answers): ... print 'What is your %s? It is %s.' % (q, a) ... What is your name? It is lancelot. What is your quest? It is the holy grail. What is your favorite color? It is blue. Để lặp qua một dãy theo thứ tự đảo, đầu tiên chỉ định dãy đó theo thứ tự xuôi, rồi gọi hàm >>> for i in reversed(xrange(1,10,2)): ... print i ... 9 7 5 3 1 Để lặp qua một dãy theo thứ tự đã sắp xếp, dùng hàm >>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana'] >>> for f in sorted(set(basket)): ... print f ... apple banana orange pear 5.7 Bàn thêm về điều kiệnĐiều kiện dùng trong các câu lệnh Các toán tử so sánh So sánh có thể được nối với nhau. Ví dụ như, Phép so sánh có thể được ghép với nhau bằng toán tử Boolean Các toán tử Boolean and và or còn được gọi là đoản mạch (short-circuit) toán tử: toán hạng của chúng được đánh giá từ trái qua phải, và việc định giá dừng lại ngay khi kết quả được xác định. Ví dụ như, nếu A và C là đúng nhưng B là sai, A and B and C không định giá biểu thức C. Khi dùng như một giá trị chung chung và không phải như một Boolean, giá trị trả về của một toán tử đoản mạch là thông số được định giá cuối cùng. Có thể gán kết quả của một phép so sánh hoặc một biểu thức Boolean vào một biến. Ví dụ, >>> string1, string2, string3 = '', 'Trondheim', 'Hammer Dance' >>> non_null = string1 or string2 or string3 >>> non_null 'Trondheim' Chú ý rằng trong Python, khác với C, phép gán không thể có mặt trong biểu thức. Các lập trình viên C sẽ không hài lòng với việc này, nhưng nó tránh một nhóm lớn các lỗi thường gặp trong chương trình C: nhập vào
5.8 So sánh dãy và các kiểu khácĐối tượng dãy có thể được so sánh với đối tượng khác cùng kiểu dãy. Sự so sánh dùng từ điển thứ tự: đầu tiên hai phần tử đâu được so sánh, và nếu chúng khác nhau thì kết quả được xác định; nếu chúng bằng nhau thì hai phần tử kế sẽ được so sánh và cứ thế, cho đến cuối một trong hai dãy. Nếu hai phần tử được so sánh lại là hai phần dãy cùng kiểu, phép so sánh từ điển lại được thực hiện đệ quy như vậy. Nếu mọi phần tử trong hai dãy đều bằng nhau thì chúng được coi là bằng nhau. Nếu một dãy là dãy con ban đầu của dãy kia, thì dãy ngắn hơn sẽ là dãy bé hơn. Thứ tự từ điển đối với chuỗi sử dụng thứ tự ASCII cho từng ký tự. Một vài ví dụ về việc so sánh dãy cùng kiểu: (1, 2, 3) < (1, 2, 4) [1, 2, 3] < [1, 2, 4] 'ABC' < 'C' < 'Pascal' < 'Python' (1, 2, 3, 4) < (1, 2, 4) (1, 2) < (1, 2, -1) (1, 2, 3) == (1.0, 2.0, 3.0) (1, 2, ('aa', 'ab')) < (1, 2, ('abc', 'a'), 4) Lưu ý rằng so sánh các đối tượng khác kiểu cũng được chấp nhận. Kết quả có thể đoán được nhưng ngoài ý muốn: các kiểu được xếp theo thứ tự tên của chúng. Do đó[3], một danh
sách ( 6. Mô-đunNếu bạn thoát khỏi trình thông dịch và chạy nó lại, những gì bạn đã định nghĩa (hàm và biến) đều bị mất. Do đó, nếu bạn muốn viết một chương trình dài hơn, thì tốt nhất bạn nên dùng một trình soạn thảo để chuẩn bị đầu vào cho trình thông dịch và chạy nó với tập tin vào này. Việc này được gọi là tạo kịch bản (script). Khi chương trình của bạn trở nên dài hơn, bạn sẽ muốn tách nó ra thành nhiều tập tin để dễ duy trì. Bạn sẽ muốn dùng một hàm thuận tiện mà bạn đã viết trong nhiều chương trình mà không cần phải chép lại định nghĩa của nó vào các chương trình đó. Để hỗ trợ việc này, Python có một cách đặt các định nghĩa vào một tập tin và dùng chúng trong một kịch bản hoặc trong một phiên làm việc với trình thông dịch. Tập tin này được gọi là mô-đun (module); các định nghĩa từ một mô-đun có thể được nhập (import) vào các mô-đun khác hoặc vào mô-đun chính (tập hợp các biến mà bạn có thể truy cập tới trong một kịch bản được chạy ở cấp cao nhất và trong chế độ máy tính). Mô-đun là một tập tin chứa các định nghĩa và câu lệnh Python. Tên tập tin là tên của mô-đun với đuôi # Fibonacci numbers module def fib(n): # write Fibonacci series up to n a, b = 0, 1 while b < n: print b, a, b = b, a+b def fib2(n): # return Fibonacci series up to n result = [] a, b = 0, 1 while b < n: result.append(b) a, b = b, a+b return result Bây giờ chạy trình thông dịch Python và nhập mô-đun này với dòng lệnh sau: >>> import fibo Việc này sẽ không nhập trực tiếp các tên hàm định nghĩa trong >>> fibo.fib(1000) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 >>> fibo.fib2(100) [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] >>> fibo.__name__ 'fibo' Nếu bạn định dùng một hàm thường xuyên, thì bạn có thể gán nó vào một tên cục bộ: >>> fib = fibo.fib >>> fib(500) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 6.1 Bàn thêm về mô-đunMô-đun có thể chứa các câu lệnh khả thi cũng như các định nghĩa hàm. Các câu lệnh này nhằm mục đích khởi tạo mô-đun. Chúng sẽ chỉ được chạy lần đầu mô-đun được nhập ở đâu đó[4]. Mỗi mô-đun có một bảng ký hiệu riêng của nó và được dùng như bảng toàn cục đối với mọi hàm được định nghĩa trong mô-đun. Do đó, tác giả của một mô-đun có thể sử dụng các biến toàn cục trong mô-đun mà không phải lo lắng về việc trùng lặp với các biến toàn cục của người dùng. Mặt khác, nếu bạn biết bạn
đang làm gì, bạn có thể truy cập vào các biến toàn cục của mô-đun với cùng một cách dùng để truy cập các hàm của nó Mô-đun có thể nhập các mô-đun khác. Thông thường (nhưng không bắt buộc) ta hay để tất cả các lệnh import ở đầu một mô-đun (hoặc kịch bản). Các tên của mô-đun bị nhập được đặt trong bảng ký hiệu toàn cục của mô-đun nhập nó. >>> from fibo import fib, fib2 >>> fib(500) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 Câu
lệnh này không đưa tên mô-đun bị nhập vào bảng ký hiệu cục bộ (do đó trong ví dụ này, >>> from fibo import * >>> fib(500) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 Câu lệnh này nhập tất cả mọi tên trừ những tên bắt đầu bằng dấu gạch chân ( 6.1.1 Đường dẫn tìm mô-đunKhi mô-đun tên spam được nhập vào, trình thông dịch sẽ tìm một tập tin tên spam.py trong thư mục hiện tại, rồi trong danh sách các thư mục được chỉ định bởi biến môi trường
PYTHONPATH. Biến này có cùng cú pháp như là biến môi trường PATH, cùng chứa một danh sách tên các thư mục. Khi PYTHONPATH chưa được thiết lập, hoặc khi tập tin không được tìm thấy, việc tìm kiếm sẽ tiếp tục tìm trong đường dẫn mặc định tùy theo khi cài Python; trên Unix, đường dẫn này thường là.:/usr/local/lib/python. 6.1.2 Các tập tin Python “đã dịch”Như một cách
quan trọng để tăng tốc quá trình khởi động của các chương trình ngắn có dùng nhiều mô-đun chuẩn, nếu tập tin có tên spam.pyc tồn tại trong thư mục mà spam.py được tìm thấy, tập tin này được giả định là phiên bản đã được “biên dịch byte” (byte-compile) của mô-đun spam. Thời gian thay đổi của phiên bản spam.py dùng để tạo spam.pyc được lưu lại trong spam.pyc, và tập tin.pyc sẽ bị bỏ qua nếu chúng không khớp nhau.
6.2 Các mô-đun chuẩnPython có một thư viện các mô-đun chuẩn, được nói tới trong một tài liệu khác, Tham khảo thư viện Python (từ nay gọi là “Tài liệu tham khảo”’). Một vài mô-đun được chuyển thẳng vào trình thông dịch; chúng
cung cấp các tác vụ không nằm trong phạm vi chính của ngôn ngữ nhưng cũng được tạo sẵn vì hiệu quả cao hoặc để truy cập vào những chức năng của hệ điều hành ví dụ như các lệnh gọi hệ thống. Tập hợp các mô-đun này là một tùy chọn cấu hình lệ thuộc vào hệ thống. Ví dụ, mô-đun >>> import sys >>> sys.ps1 '>>> ' >>> sys.ps2 '... ' >>> sys.ps1 = 'C> ' C> print 'Yuck!' Yuck! C> Hai
biến này chỉ được định nghĩa khi trình thông dịch chạy ở chế độ tương tác. >>> import sys >>> sys.path.append('/ufs/guido/lib/python') 6.3 Hàm dir()Hàm có sẵn >>> import fibo, sys >>> dir(fibo) ['__name__', 'fib', 'fib2'] >>> dir(sys) ['__displayhook__', '__doc__', '__excepthook__', '__name__', '__stderr__', '__stdin__', '__stdout__', '_getframe', 'api_version', 'argv', 'builtin_module_names', 'byteorder', 'callstats', 'copyright', 'displayhook', 'exc_clear', 'exc_info', 'exc_type', 'excepthook', 'exec_prefix', 'executable', 'exit', 'getdefaultencoding', 'getdlopenflags', 'getrecursionlimit', 'getrefcount', 'hexversion', 'maxint', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setdlopenflags', 'setprofile', 'setrecursionlimit', 'settrace', 'stderr', 'stdin', 'stdout', 'version', 'version_info', 'warnoptions'] Không có thông số, >>> a = [1, 2, 3, 4, 5] >>> import fibo >>> fib = fibo.fib >>> dir() ['__builtins__', '__doc__', '__file__', '__name__', 'a', 'fib', 'fibo', 'sys'] Lưu ý rằng nó liệt kê mọi loại tên: biến, mô-đun, hàm, v.v…
>>> import __builtin__ >>> dir(__builtin__) ['ArithmeticError', 'AssertionError', 'AttributeError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FloatingPointError', 'FutureWarning', 'IOError', 'ImportError', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '_', '__debug__', '__doc__', '__import__', '__name__', 'abs', 'apply', 'basestring', 'bool', 'buffer', 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'min', 'object', 'oct', 'open', 'ord', 'pow', 'property', 'quit', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip'] 6.4 GóiGói (package) là một cách để cấu trúc vùng tên mô-đun của Python bằng cách dùng “tên mô-đun có
chấm”. Ví dụ, tên mô-đun Sound/ Top-level package __init__.py Initialize the sound package Formats/ Subpackage for file format conversions __init__.py wavread.py wavwrite.py aiffread.py aiffwrite.py auread.py auwrite.py ... Effects/ Subpackage for sound effects __init__.py echo.py surround.py reverse.py ... Filters/ Subpackage for filters __init__.py equalizer.py vocoder.py karaoke.py ... Khi nhập một gói, Python tìm trong các thư mục từ Các tập tin Người dùng gói này có thể nhập từng mô-đun riêng lẻ từ gói, ví dụ: import Sound.Effects.echo Nó sẽ nạp mô-đun con Sound.Effects.echo.echofilter(input, output, delay=0.7, atten=4) Cách nhập mô-đun con khác là: from Sound.Effects import echo Nó cũng nạp luôn mô-đun con echo.echofilter(input, output, delay=0.7, atten=4) Một biến thể khác là nhập hàm hoặc biến mình muốn một cách trực tiếp: from Sound.Effects.echo import echofilter Một lần nữa, lệnh này nạp mô-đun con echo, nhưng nó làm hàm echofilter(input, output, delay=0.7, atten=4) Lưu ý rằng khi sử dụng 6.4.1 Nhập * từ một góiBây giờ chuyện gì xảy ra khi bạn viết Giải pháp duy nhất là để tác giả gói chỉ định rõ chỉ mục của gói. Câu lệnh import dùng
cách thức sau: nếu mã __all__ = ["echo", "surround", "reverse"] Điều này có nghĩa là import Sound.Effects.echo import Sound.Effects.surround from Sound.Effects import * Trong ví dụ này, các mô-đun
6.4.2 Tham chiếu nội trong góiCác mô-đun con thường cần tham chiếu lẫn nhau. Ví dụ, Mô-đun from. import echo from.. import Formats from..Filters import equalizer Lưu ý cả hai lệnh nhập tương đối xác định và hiểu ngầm đều dựa vào tên của mô-đun hiện
tại. Vì tên của mô-đun chính luôn luôn là “ 6.4.3 Gói trong nhiều thư mụcGói còn có thêm một thuộc tính đặc biệt khác, 7. Vào và ra (nhập và xuất) trong lập trình PythonCó nhiều các để thể hiện đầu ra của một chương trình; dữ liệu có thể được in ra ở dạng người đọc được, hoặc viết vào một tập tin để dùng sau này. Chương này sẽ bàn về một vài khả năng đó. 7.1 Định dạng ra đẹp hơnChúng ta đã gặp hai cách để viết giá trị: câu lệnh biểu thức và câu lệnh Lưu ý, từ Python 3x trở lên thì lệnh Thông thường bạn sẽ muốn điều khiển cách định dạng đầu ra của bạn nhiều hơn là chỉ đơn giản là in các giá trị phân cách bởi
khoảng trắng. Có hai cách để định dạng đầu ra của bạn; cách thứ nhất là bạn tự xử lý các chuỗi; dùng phép cắt miếng của chuỗi và phép ghép chuỗi bạn có thể tạo bất kỳ bố cục nào bạn có thể nghĩ ra. Mô-đun chuẩn Một câu hỏi vẫn còn đó: làm sao để chuyển giá trị thành chuỗi? May mắn thay Python có một cách để chuyển bất kỳ giá trị nào thành chuỗi: truyền nó vào hàm
Một vài ví dụ: >>> s = 'Hello, world.' >>> str(s) 'Hello, world.' >>> repr(s) "'Hello, world.'" >>> str(0.1) '0.1' >>> repr(0.1) '0.10000000000000001' >>> x = 10 * 3.25 >>> y = 200 * 200 >>> s = 'The value of x is ' + repr(x) + ', and y is ' + repr(y) + '...' >>> print s The value of x is 32.5, and y is 40000... >>> # The repr() of a string adds string quotes and backslashes: ... hello = 'hello, world\n' >>> hellos = repr(hello) >>> print hellos 'hello, world\n' >>> # The argument to repr() may be any Python object: ... repr((x, y, ('spam', 'eggs'))) "(32.5, 40000, ('spam', 'eggs'))" >>> # reverse quotes are convenient in interactive sessions: ... `x, y, ('spam', 'eggs')` "(32.5, 40000, ('spam', 'eggs'))" Đây là hai cách để viết một bảng bình phương và lập phương: >>> for x in range(1, 11): ... print repr(x).rjust(2), repr(x*x).rjust(3), ... # Note trailing comma on previous line ... print repr(x*x*x).rjust(4) ... 1 1 1 2 4 8 3 9 27 4 16 64 5 25 125 6 36 216 7 49 343 8 64 512 9 81 729 10 100 1000 >>> for x in range(1,11): ... print '%2d %3d %4d' % (x, x*x, x*x*x) ... 1 1 1 2 4 8 3 9 27 4 16 64 5 25 125 6 36 216 7 49 343 8 64 512 9 81 729 10 100 1000 (Chú ý một khoảng trắng được thêm vào giữa các cột theo cách hoạt động của Có một phương thức khác, >>> '12'.zfill(5) '00012' >>> '-3.14'.zfill(7) '-003.14' >>> '3.14159265359'.zfill(5) '3.14159265359' Dùng toán tử >>> import math >>> print 'The value of PI is approximately %5.3f.' % math.pi The value of PI is approximately 3.142. Nếu có nhiều hơn một định dạng trong chuỗi, bạn cần truyền một bộ ở toán hạng bên phải, như trong ví dụ này: >>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678} >>> for name, phone in table.items(): ... print '%-10s ==> %10d' % (name, phone) ... Jack ==> 4098 Dcab ==> 7678 Sjoerd ==> 4127 Hầu
hết các định dạng hoạt động như trong C và yêu cầu bạn truyền kiểu thích hợp; nếu không, bạn sẽ nhận biệt lệ thay vì đổ nhân (core dump). Định dạng Nếu bạn có một chuỗi định dạng rất dài và không
muốn cắt ra, có thể bạn sẽ muốn tham chiếu tới các biến sắp được định dạng qua tên, thay vì vị trí. Việc này có thể được thực hiện theo dạng >>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678} >>> print 'Jack: %(Jack)d; Sjoerd: %(Sjoerd)d; Dcab: %(Dcab)d' % table Jack: 4098; Sjoerd: 4127; Dcab: 8637678 Cách này đặc biệt hữu dụng khi đi kèm với hàm có sẵn 7.2 Đọc và viết tập tinCâu lệnh >>> f=open('/tmp/workfile', 'w') >>> print f Thông số thứ nhất là một
chuỗi chứa tên tập tin. Thông số thứ hai là một chuỗi khác chứa một vài ký tự xác định cách thức tập tin sẽ được dùng. Trong Windows và Macintosh,
‘ 7.2.1 Phương thức của đối tượng tập tinCác ví dụ trong mục này sẽ giả sử một đối tượng tập tin f đã được tạo. Để đọc nội dung tập tin, gọi >>> f.read() 'This is the entire file.\n' >>> f.read() ''
>>> f.readline() 'This is the first line of the file.\n' >>> f.readline() 'Second line of the file\n' >>> f.readline() ''
>>> f.readlines() ['This is the first line of the file.\n', 'Second line of the file\n'] Một cách khác để đọc các dòng là lặp qua đối tượng tập tin. Nó rất tiết kiệm bộ nhớ, nhanh, và có mã đơn giản: >>> for line in f: print line, This is the first line of the file. Second line of the file Cách này đơn giản hơn nhưng không cho bạn điều khiển cách đọc. Vì hai cách này quản lý bộ đệm dòng khác nhau, chúng không nên được dùng chung. >>> f.write('This is a test\n') Để viết một thứ khác không phải là chuỗi, nó sẽ cần được chuyển thành một chuỗi trước: >>> value = ('the answer', 42) >>> s = str(value) >>> f.write(s)
>>> f = open('/tmp/workfile', 'r+') >>> f.write('0123456789abcdef') >>> f.seek(5) # Go to the 6th byte in the file >>> f.read(1) '5' >>> f.seek(-3, 2) # Go to the 3rd byte before the end >>> f.read(1) 'd' Khi bạn đã dùng xong, gọi >>> f.close() >>> f.read() Traceback (most recent call last): File " Các đối tượng tập tin có thêm các phương thức phụ như 7.2.2 pickle mô-đunCác chuỗi có thể được ghi hoặc đọc dễ dàng từ một tập tin. Các số cần một ít cố gắng hơn, vì phương thức Thay vì để người dùng luôn viết và gỡ rối mã để lưu các kiểu dữ liệu phức tạp, Python cung cấp một mô-đun chuẩn gọi là pickle. Đây là một mô-đun tuyệt diệu có thể nhận hầu hết mọi đối tượng Python (ngay cả một vài dạng mã Python!), và chuyển nó thành một chuỗi; quá trình này được gọi là giầm (pickling). Tạo lại đối tượng từ một chuỗi được gọi là vớt (unpickling). Giữa việc giầm và vớt, biểu diễn dạng chuỗi của đối tượng có thể được lưu vào tập tin, hoặc gửi qua mạng đến một máy ở xa. Nếu bạn có một đối tượng pickle.dump(x, f) Để vớt đối tượng ra, nếu x = pickle.load(f) (Có những biến thể khác, dùng khi giầm nhiều đối tượng hoặc khi bạn không muốn viết dữ liệu đã giầm vào tập tin; tham khảo toàn bộ tài liệu về pickle trong Tham khảo thư viện Python.) pickle là cách chuẩn để làm cho các đối tượng Python có thể được lưu và dùng lại bởi các chương trình khác, hoặc bởi lần chạy khác của cùng chương trình; thuật ngữ trong ngành gọi là đối tượng bền. Vì pickle được sử dụng rộng rãi, nhiều tác giả khi mở rộng Python đã cẩn thận để đảm bảo rằng các kiểu dữ liệu mới ví dụ như ma trận có thể được giầm và vớt đúng đắn. 8. Lỗi và biệt lệĐến bây giờ chũng ta cũng chỉ mới nhắc đến các thông điệp lỗi, nhưng nếu bạn đã thử qua các ví dụ thì bạn có thể đã gặp nhiều hơn. Có (ít nhất) hai loại lỗi khác biệt: lỗi cú pháp và biệt lệ. 8.1 Lỗi cú phápLỗi cú pháp, còn biết đến như lỗi phân tích (parsing error), có lẽ là phàn nàn lớn nhất bạn gặp phải khi vẫn đang học Python: >>> while True print 'Hello world' File " Bộ phân tích lặp lại dòng gây lỗi và hiển thị một mũi tên nhỏ trỏ vào điểm đầu tiên lỗi được phát hiện. Lỗi nằm ở
dấu hiệu phía trước mũi tên: trong ví dụ trên, lỗi được phát hiện ở từ khóa 8.2 Biệt lệ (Ngoại lệ)Cho dù một câu lệnh hoặc biểu thức là đúng đắn, nó vẫn có thể tạo lỗi khi thực thi. Những lỗi bị phát hiện trong lúc thực thi được gọi là biệt lệ và không tai hại một cách vô điều kiện: bạn sẽ học cách xử lý chúng trong các chương trình Python. Hầu hết các biệt lệ đều được xử lý bởi chương trình và dẫn đến kết quả là các thông điệp lỗi như ở đây: >>> 10 * (1/0) Traceback (most recent call last): File " Dòng cuối cùng của thông điệp lỗi cho biết chuyện gì xảy ra. Biệt lệ có nhiều kiểu, và kiểu được hiển thị như là một phần của thông điệp: các kiểu trong ví dụ là Phần trước của thông điệp lỗi cho biết hoàn cảnh khi xảy ra biệt lệ, ở dạng lần ngược ngăn xếp (stack traceback). Bình thường nó chứa một lần ngược ngăn xếp liệt kê các dòng nguồn; tuy nhiên, nó sẽ không hiển thị các dòng đọc từ đầu vào chuẩn. 8.3 Xử lý biệt lệChúng ta có thể viết những chương trình xử lý những biệt lệ được chọn. Hãy xem ví dụ sau, nó yêu cầu người dùng nhập vào dữ liệu cho tới khi một số nguyên được nhập, nhưng cũng cho phép người dùng ngưng chương trình (dùng Control-C hoặc phím tắt khác mà hệ điều hành hỗ trợ); lưu ý rằng sự ngắt quãng do người dùng tạo nên được đánh dấu bởi việc nâng biệt lệ >>> while True: ... try: ... x = int(raw_input("Please enter a number: ")) ... break ... except ValueError: ... print "Oops! That was no valid number. Try again..." ...
Một câu lệnh ... except (RuntimeError, TypeError, NameError): ... pass Vế import sys try: f = open('myfile.txt') s = f.readline() i = int(s.strip()) except IOError, (errno, strerror): print "I/O error(%s): %s" % (errno, strerror) except ValueError: print "Could not convert data to an integer." except: print "Unexpected error:", sys.exc_info()[0] raise Câu lệnh for arg in sys.argv[1:]: try: f = open(arg, 'r') except IOError: print 'cannot open', arg else: print arg, 'has', len(f.readlines()), 'lines' f.close() Việc dùng vế >>> try: ... raise Exception('spam', 'eggs') ... except Exception, inst: ... print type(inst) # the exception instance ... print inst.args # arguments stored in.args ... print inst # __str__ allows args to printed directly ... x, y = inst # __getitem__ allows args to be unpacked directly ... print 'x =', x ... print 'y =', y ... Nếu biệt lệ có một thông số, nó sẽ được in ra như là phần cuối (`chi tiết’) của thông điệp của những biệt lệ không được xử lý. >>> def this_fails(): ... x = 1/0 ... >>> try: ... this_fails() ... except ZeroDivisionError, detail: ... print 'Handling run-time error:', detail ... Handling run-time error: integer division or modulo by zero 8.4 Nâng biệt lệCâu lệnh >>> raise NameError, 'HiThere' Traceback (most recent call last): File " Thông số đầu tiên cho raise chỉ định biệt lệ sẽ được nâng. Thông số (tùy chọn) thứ hai chỉ định thông số của biệt lệ. Hoặc là, các dòng trên có thể được viết >>> try: ... raise NameError, 'HiThere' ... except NameError: ... print 'An exception flew by!' ... raise ... An exception flew by! Traceback (most recent call last): File " 8.5 Biệt lệ tự định nghĩaCác chương trình có thể đặt tên biệt lệ riêng bằng cách tạo một lớp biệt lệ mới. Các biệt lệ thường nên kế thừa từ lớp >>> class MyError(Exception): ... def __init__(self, value): ... self.value = value ... def __str__(self): ... return repr(self.value) ... >>> try: ... raise MyError(2*2) ... except MyError, e: ... print 'My exception occurred, value:', e.value ... My exception occurred, value: 4 >>> raise MyError, 'oops!' Traceback (most recent call last): File " Trong ví dụ này, mặc định Các lớp biệt lệ có thể được định nghĩa để làm bất kỳ việc gì như các lớp khác, nhưng chúng thường là đơn giản và chỉ cung cấp một số thuộc tính để chứa thông tin về lỗi cho các phần xử lý biệt lệ. Khi tạo một mô-đun mà có thể nâng vài lỗi khác biệt, cách thông thường là tạo một lớp cơ sở cho các biệt lệ được định nghĩa bởi mô-đun đó, và kế thừa từ đó để tạo những lớp biệt lệ cụ thể cho những trường hợp lỗi khác nhau: class Error(Exception): """Base class for exceptions in this module.""" pass class InputError(Error): """Exception raised for errors in the input. Attributes: expression -- input expression in which the error occurred message -- explanation of the error """ def __init__(self, expression, message): self.expression = expression self.message = message class TransitionError(Error): """Raised when an operation attempts a state transition that's not allowed. Attributes: previous -- state at beginning of transition next -- attempted new state message -- explanation of why the specific transition is not allowed """ def __init__(self, previous, next, message): self.previous = previous self.next = next self.message = message Đa số biệt lệ được định nghĩa với tên tận cùng bằng “ 8.6 Định nghĩa cách xử lýCâu lệnh >>> try: ... raise KeyboardInterrupt ... finally: ... print 'Goodbye, world!' ... Goodbye, world! Traceback (most recent call last): File " A vế
>>> def divide(x, y): ... try: ... result = x / y ... except ZeroDivisionError: ... print "division by zero!" ... else: ... print "result is", result ... finally: ... print "executing finally clause" ... >>> divide(2, 1) result is 2 executing finally clause >>> divide(2, 0) division by zero! executing finally clause >>> divide("2", "1") executing finally clause Traceback (most recent call last): File " Như
bạn có thể thấy, vế 8.7 Định nghĩa xử lý có sẵnMột số đối tượng định nghĩa các tác vụ dọn dẹp chuẩn để thực thi khi một đối tượng không còn được cần đến, cho dù việc xử dụng đối tượng là thành công hay thất bại. Xem qua ví dụ sau, nó thử mở một tập tin và viết nội dung của nó ra màn hình. for line in open("myfile.txt"): print line Vấn đề với đoạn mã trên là nó để tập tin ngỏ trong một thời gian không xác định sau khi đoạn mã đã kết thúc. Đây không phải là vấn đề gì trong các đoạn kịch bản đơn giản, nhưng có thể là một vấn đề phức tạp đối với các ứng dụng lớn hơn. Câu lệnh with open("myfile.txt") as f: for line in f: print line Sau khi câu lệnh được thực thi, tập tin 9. LớpChỉ cần một ít cú pháp và từ khóa mới, Python đã có thể hỗ trợ lớp Theo thuật ngữ C++, mọi thành viên lớp (kể cả thành viên dữ liệu) là 9.1 Vài lời về thuật ngữNhững từ chuyên ngành dùng ở đây theo từ vựng của Smalltalk và C++. Các đối tượng có tính cá thể (individuality), và nhiều tên (trong nhiều phạm vi, scope) có thể được gắn vào cùng một đối tượng. Trong các ngôn ngữ khác được gọi là tên lóng (alias). Nó thường không được nhận ra khi dùng Python lần đầu, và có thể được bỏ qua khi làm việc với các kiểu bất biến cơ bản (số, chuỗi, bộ). Tuy nhiên, tên lóng có một ảnh hưởng đối với ý nghĩa của mã Python có sử dụng các đối tượng khả biến như danh sách, từ điển, và đa số các kiểu thể hiện các vật ngoài chương trình (tập tin, cửa sổ, v.v…). Nó thường được dùng vì tên lóng có tác dụng như là con trỏ theo một vài khía cạnh nào đó. Ví dụ, truyền một đối tượng vào một hàm rẻ vì chỉ có con trỏ là được truyền, và nếu một hàm thay đổi một đối tượng được truyền vào, thì nơi gọi sẽ thấy các thay đổi đó — thay vì cần hai kiểu truyền thông số như trong Pascal. 9.2 Phạm vi trong Python và vùng tênTrước
khi giới thiệu lớp, chúng ta sẽ cần hiểu phạm vi (scope) và vùng tên (namespace) hoạt động như thế nào vì các định nghĩa lớp sẽ sử dụng chúng. Kiến thức về vấn đề này cũng rất hữu dụng với những nhà lập trình Python chuyên nghiệp. Một namespace (vùng tên) là ánh xạ từ tên vào đối tượng. Đa số các vùng tên được cài đặt bằng từ điển Python, nhưng điều đó thường là không quan trọng (trừ tốc độ), và có thể sẽ thay đổi trong tương lai. Các ví dụ vùng tên
như: tập hợp các tên có sẵn (các hàm như Cũng xin nói
thêm là từ thuộc tính được dùng để chỉ mọi tên theo sau dấu chấm — ví dụ, trong biểu thức Thuộc tính có thể là chỉ đọc, hoặc đọc ghi. Trong trường hợp sau, phép gán vào thuộc tính có thể được thực hiện. Các thuộc tính mô-đun là đọc ghi: bạn có thể viết “ Các vùng tên được tạo ra vào những lúc khác nhau và có thời gian sống khác nhau. Vùng tên chứa các tên có sẵn được tạo ra khi trình thông dịch Python bắt đầu, và
không bao giờ bị xóa đi. Vùng tên toàn cục của một mô-đun được tạo ra khi định nghĩa mô-đun được đọc; bình thường, vùng tên mô-đun cũng tồn tại cho tới khi trình thông dịch thoát ra. Các câu lệnh được thực thi bởi lời gọi ở lớp cao nhất của trình thông dịch, vì đọc từ một kịch bản hoặc qua tương tác, được coi như một phần của mô-đun gọi là Một phạm vi là một vùng văn bản của một chương trình Python mà một vùng tên có thể được truy cập trực tiếp. “Có thể truy cập trực tiếp” có nghĩa là một tham chiếu không đầy đủ (unqualifed reference) tới một tên sẽ thử tìm tên đó trong vùng tên. Mặc dù phạm vi được xác định tĩnh, chúng được dùng một cách động. Vào bất kỳ một lúc nào, có ít nhất ba phạm vi lồng nhau mà vùng tên của chúng có thể được truy cập trực tiếp: phạm vi bên trong cùng, được tìm trước, chứa các tên nội bộ; các vùng tên của các hàm chứa nó, được tìm bắt đầu từ phạm vi chứa nó gần nhất (nearest enclosing scope); phạm vi giữa (middle scope), được tìm kế, chứa các tên toàn cục của mô-đun; và phạm vi ngoài cùng (được tìm sau cùng) là vùng tên chứa các tên có sẵn. Nếu một tên được khai báo là toàn cục, thì mọi tham chiếu hoặc phép
gán sẽ đi thẳng vào phạm vi giữa chứa các tên toàn cục của mô-đun. Nếu không, mọi biến được tìm thấy ngoài phạm vi trong cùng chỉ có thể được đọc (nếu thử khi vào các biến đó sẽ tạo một biến cục bộ mới trong phạm vi trong vùng, và không ảnh hưởng tới biến cùng tên ở phạm vi ngoài). Một điểm ngộ của Python là các phép gán luôn gán vào phạm vi trong cùng. Phép gán không chép dữ liệu — chú chỉ buộc các tên và các đối tượng. Xóa cũng vậy: câu lệnh “del x” bỏ ràng buộc x khỏi vùng tên được tham chiếu tới bởi phạm vi nội bộ. Thực tế là mọi tác vụ có thêm các tên mới đều dùng phạm vi nội bộ: điển hình là các câu lệnh nhập và các định nghĩa hàm buộc tên mô-đun hoặc tên hàm vào phạm vi nội bộ. (Lệnh global có thể được dùng để cho biết một biến cụ thể là ở phạm vi toàn cục.) 9.3 Cái nhìn đầu tiên về lớpLớp thêm một ít cú pháp mới, ba kiểu đối tượng mới, và một ít ngữ nghĩa mới. 9.3.1 Cú pháp định nghĩa lớpKiểu đơn giản nhất của việc định nghĩa lớp nhìn giống như: class ClassName: Định nghĩa lớp, cũng như định nghĩa hàm (câu lệnh Trong thực tế, các câu lệnh trong một định nghĩa lớp thường là định nghĩa hàm, nhưng các câu lệnh khác cũng được cho phép, và đôi khi rất hữu dụng. Các định nghĩa hàm trong một lớp thường có một dạng danh sách thông số lạ, vì phải tuân theo cách gọi phương thức. Khi gặp phải một định nghĩa lớp, một vùng tên mới được tạo ra, và được dùng như là phạm vi nội bộ — do đó, mọi phép gán vào các biến nội bộ đi vào vùng tên này. Đặc biệt, các định nghĩa hàm buộc tên của hàm mới ở đây. Khi rời khỏi một định nghĩa lớp một cách
bình thường, một đối tượng lớp được tạo ra. Đây cơ bản là một bộ gói (wrapper) của nội dung của vùng tên tạo ra bởi định nghĩa lớp. Phạm vi nội bộ ban đầu (trước khi vào định nghĩa lớp) được thiết lập lại, và đối tượng lớp được buộc vào đây qua tên lớp đã chỉ định ở định nghĩa lớp, ( 9.3.2 Đối tượng lớpCác đối tượng lớp hỗ trợ hai loại tác vụ: tham chiếu thuộc tính và tạo trường hợp (instantiation). Tham chiếu thuộc tính dùng cú pháp chuẩn được dùng
cho mọi tham chiếu thuộc tính trong Python: class MyClass: "A simple example class" i = 12345 def f(self): return 'hello world' thì Class instantiation (tạo trường hợp lớp) dùng cùng cách viết như gọi hàm. Hãy tưởng tượng một đối tượng lớp là một hàm không thông số trả về một trường hợp của lớp. Ví dụ (với lớp trên): x = MyClass() tạo một trường hợp mới của lớp và gán đối tượng này vào biến nội bộ Tác vụ tạo trường hợp (“gọi” một đối tượng lớp) tạo một đối tượng rỗng. Nhiều lớp thích tạo đối tượng với các trường hợp được khởi tạo ở một trạng thái đầu nào đó. Do đó một lớp có thể
định nghĩa một phương thức đặc biệt tên def __init__(self): self.data = [] Khi một lớp định nghĩa một phương thức x = MyClass() Dĩ nhiên, >>> class Complex: ... def __init__(self, realpart, imagpart): ... self.r = realpart ... self.i = imagpart ... >>> x = Complex(3.0, -4.5) >>> x.r, x.i (3.0, -4.5) 9.3.3 Đối tượng trường hợpChúng
ta có thể làm được gì với những đối tượng trường hợp? Tác vụ duy nhất mà các đối tượng trường hợp hiểu được là tham chiếu thuộc tính. Có hai loại tên thuộc tính hợp lệ, thuộc tính dữ liệu và phương thức. x.counter = 1 while x.counter < 10: x.counter = x.counter * 2 print x.counter del x.counter Loại tham chiếu thuộc tính trường hợp khác là một method (phương thức). Một phương thức là một hàm “của” một đối tượng. (Trong Python, từ phương thức không chỉ riêng cho trường hợp lớp: các kiểu đối tượng khác cũng có thể có phương thức. Ví dụ, đối tượng danh sách có phương thức tên Các tên phương thức hợp lệ của một đối tượng trường hợp phụ thuộc vào lớp của nó. Theo định nghĩa, mọi thuộc tính của một lớp mà là những đối tượng hàm định nghĩa các phương thức tương ứng của các trường hợp của lớp đó. Trong ví dụ của chúng ta, 9.3.4 Đối tượng phương thứcThông thường, một phương thức được gọi ngay sau khi nó bị buộc: x.f() Trong xf = x.f while True: print xf() sẽ tiếp tục in Thật ra, bạn cũng có thể đã đoán ra được câu trả lời: điểm đặc biệt của phương thức là đối tượng đó được truyền vào ở thông số đầu tiên của hàm. Trong ví dụ của chúng ta, lời gọi 9.4 Một vài lời bìnhThuộc tính dữ liệu sẽ che thuộc tính
phương thức cùng tên; để tránh vô tình trùng lặp tên, mà có thể dẫn đến các lỗi rất khó tìm ra trong các chương trình lớn, bạn nên có một quy định đặt tên nào đó để giảm thiểu tỉ lệ trùng lặp. Các quy định khả thi có thể gồm viết hoa tên phương thức, đặt tiền tố vào các tên thuộc tính dữ liệu (ví dụ như dấu gạch dưới Các thuộc tính dữ liệu có thể được tham chiếu tới bởi cả phương thức lẫn người dùng đối tượng đó. Nói một cách khác, lớp không thể được dùng để cài đặt các kiểu dữ liệu trừu tượng tuyệt đối. Trong thực tế, không có gì trong Python có thể ép việc che dấu dữ liệu — tất cả đều dựa trên nguyên tắc. (Mặt khác, cài đặt Python, được viết bằng C, có thể dấu các chi tiết cài đặt và điểu khiển truy cập vào một đối tượng nếu cần; điều này có thể được dùng trong các bộ mở rộng Python viết bằng C.) Người dùng nên dùng các thuộc tính dữ liệu một cách cẩn thận — người dùng có thể phá hỏng những bất biến (invariant) được giữ bởi các phương thức nếu cố ý sửa các thuộc tính dữ liệu. Lưu ý rằng người dùng có thể thêm các thuộc tính dữ liệu riêng của hộ vào đối tượng trường hợp mà không làm ảnh hưởng tính hợp lệ của các phương thức, miễn là không có trùng lặp tên — xin nhắc lại, một quy tắc đặt tên có thể giảm bớt sự đau đầu ở đây. Không có cách ngắn gọn để tham chiếu tới thuộc tính dữ liệu (hoặc các phương thức khác!) từ trong phương thức. Điều này thật ra giúp chúng ta dễ đọc mã vì không có sự lẫn lộn giữa biến nội bộ và biến trường hợp. Thông số đầu tiên của phương thức thường được gọi là self. Đây cũng chỉ là một quy ước: tên Bất kỳ đối tượng hàm nào mà là thuộc tính của một lớp sẽ định nghĩa một phương thức cho các trường hợp của lớp đó. Không nhất thiết định nghĩa hàm phải nằm trong định nghĩa lớp trên văn bản: gán một đối tượng hàm vào một biến nội bộ trong lớp cũng được. Ví dụ: # Function defined outside the class def f1(self, x, y): return min(x, x+y) class C: f = f1 def g(self): return 'hello world' h = g Bây giờ class Bag: def __init__(self): self.data = [] def add(self, x): self.data.append(x) def addtwice(self, x): self.add(x) self.add(x) Phương thức có thể tham chiếu tới các tên toàn cục theo cùng một cách như các hàm thông thường. Phạm vi toàn cục của một phương thức là mô-đun chứa định nghĩa lớp. (Phạm vi toàn cục không bao giờ là lớp!) Trong khi bạn ít gặp việc sử dụng dữ liệu toàn cục trong một phương thức, có những cách dùng hoàn toàn chính đáng: ví dụ như hàm và mô-đun được nhập vào phạm vi toàn cục có thể được sử dụng bởi phương thức, cũng như hàm và lớp được định nghĩa trong đó. Thông thường, lớp chứa các phương thức này được định nghĩa ngay trong phạm vi toàn cục, và trong phần kế đây chúng ta sẽ thấy tại sao một phương thức muốn tham chiếu tới chính lớp của nó! 9.5 Kế thừaDĩ nhiên, một tính năng ngôn ngữ sẽ không đáng được gọi là “lớp” nếu nó không hỗ trợ kế thừa. Cú pháp của một định nghĩa lớp con như sau: class DerivedClassName(BaseClassName): Tên class DerivedClassName(modname.BaseClassName): Việc thực thi định nghĩa lớp con tiến hành như là lớp cơ sở. Khi một đối tượng lớp được tạo ra, lớp cơ sở sẽ được nhớ. Nó được dùng trong việc giải các tham chiếu thuộc tính: nếu một thuộc tính không được tìm thấy ở trong lớp, việc tìm kiếm sẽ tiếp tục ở lớp cơ sở. Luật này sẽ được lặp lại nếu lớp cơ sở kế thừa từ một lớp khác. Không có gì đặc biệt trong việc tạo trường hợp của các lớp con: Lớp con có thể định nghĩa lại các phương thức của lớp cơ sở. Bởi vì phương thức không có quyền gì đặc biệt khi gọi một phương thức của cùng một đối tượng, một phương thức của lớp cơ sở gọi một
phương thức khác được định nghĩa trong cùng lớp cơ sở có thể là đang gọi một phương thức do lớp con đã định nghĩa lại. (Người dùng C++ có thể hiểu là mọi phương thức của Python là virtual.) 9.5.1 Đa kế thừaPython cũng hỗ trợ một dạng đa kế thừa hạn chế. Một định nghĩa lớp với nhiều lớp cơ sở có dạng sau: class DerivedClassName(Base1, Base2, Base3): Luật duy nhất cần để giải thích ý nghĩa là luật giải các tham chiếu thuộc tính của lớp. Nó tuân theo luật tìm theo chiều sâu, và tìm trái qua phải. Do đó, nếu một thuộc tính không được tìm ra trong Ai cũng biết rằng việc dùng đa kế thừa bừa bãi là một cơn ác mộng cho bảo trì, đặc biệt là Python dựa vào quy ước để tránh trùng lặp tên. Một vấn đề cơ bản với đa kế thừa là một lớp con của hai lớp mà có cùng một lớp cơ sở. Mặc dù dễ hiểu chuyện gì xảy ra trong vấn đề này (trường hợp sẽ có một bản chép duy nhất của “các biến trường hợp” của các thuộc tính dữ liệu dùng bởi lớp cơ sở chung), nó không rõ cho lắm nếu các ý nghĩa này thật sự hữu ích. 9.6 Biến riêngCó một dạng hỗ trợ nho nhỏ nho các từ định danh riêng của lớp (class-private identifier). Các từ định danh có dạng Xáo trộn tên nhằm cung cấp cho các lớp một cách định nghĩa dễ dàng các biến và phương thức “riêng”, mà không phải lo về các biến trường hợp được định nghĩa bởi lớp con, hoặc
việc sử dụng biến trường hợp bởi mã bên ngoài lớp. Lưu ý rằng việc xáo trộn tên được thiết kế chủ yếu để tránh trùng lặp; người quyết tâm vẫn có thể truy cập hoặc thay đổi biến riêng. Và điều này cũng có thể có ích trong các trường hợp đặc biệt, như trong trình gỡ rối, và đó là một lý do tại sao lỗ hổng này vẫn chưa được vá. 9.7 Những điều khácĐôi khi nó thật là hữu ích khi có một kiểu dữ liệu giống như Pascal “record” hoặc C “struct”, gói gọn vài mẩu dữ liệu vào chung với nhau. Một định nghĩa lớp rỗng thực hiện được việc này: class Employee: pass john = Employee() # Create an empty employee record # Fill the fields of the record john.name = 'John Doe' john.dept = 'computer lab' john.salary = 1000 Với mã Python cần một kiểu dữ liệu trừu tượng, ta có thể thay vào đó một lớp
giả lập các phương thức của kiểu dữ liệu đó. Ví dụ, nếu bạn có một hàm định dạng một vài dữ liệu trong một đối tượng tập tin, bạn có thể định nghĩa một lớp với các phương thức Các đối tượng phương trức trường hợp cũng có thuộc tính: 9.8 Biệt lệ cũng là lớpCác biệt lệ được định nghĩa bởi người dùng cũng được định danh theo lớp. Bằng cách này, một hệ thống phân cấp biệt lệ có thể được tạo ra. raise Class, instance raise instance Trong dạng đầu, raise instance.__class__, instance Lớp trong vế class B: pass class C(B): pass class D(C): pass for c in [B, C, D]: try: raise c() except D: print "D" except C: print "C" except B: print "B" Nếu các vế 9.9 Bộ lặpBây giờ có lẽ
bạn đã lưu ý rằng hầu hết các đối tượng chứa (container object) có thể được lặp qua bằng câu lệnh for element in [1, 2, 3]: print element for element in (1, 2, 3): print element for key in {'one':1, 'two':2}: print key for char in "123": print char for line in open("myfile.txt"): print line Kiểu truy xuất này rõ ràng, súc tích, và tiện lợi. Bộ lặp ( >>> s = 'abc' >>> it = iter(s) >>> it Chúng ta đã hiểu giao thức bộ lặp, nên chúng ta có thể thêm cách thức bộ lặp (iterator behavior) vào lớp của chúng ta một cách dễ dàng. Định nghĩa một phương thức class Reverse: "Iterator for looping over a sequence backwards" def __init__(self, data): self.data = data self.index = len(data) def __iter__(self): return self def next(self): if self.index == 0: raise StopIteration self.index = self.index - 1 return self.data[self.index] >>> for char in Reverse('spam'): ... print char ... m a p s 9.10 Bộ tạoBộ sinh ( def reverse(data): for index in range(len(data)-1, -1, -1): yield data[index] >>> for char in reverse('golf'): ... print char ... f l o g Bất kỳ việc gì có thể được thực hiện với bộ sinh cũng có thể được thực hiện với các bộ lặp dựa trên lớp như đã bàn đến ở phần trước. Điều khiến bộ sinh nhỏ gọn là các phương thức 9.11 Biểu thức bộ tạoMột vài bộ sinh đơn giản có thể được viết một cách xúc tích như các biểu thức bằng cách dùng một cú pháp giống như gộp danh sách (list comprehension) nhưng với ngoặc tròn thay vì ngoặc vuông. Các biểu thức này được thiết kế cho những khi bộ sinh được sử dụng ngay lập tức bởi hàm chứa nó. Biểu thức bộ sinh gọn hơn nhưng ít khả chuyển hơn là các định nghĩa bộ sinh đầy đủ và thường chiếm ít bộ nhớ hơn là gộp danh sách tương đương. >>> sum(i*i for i in range(10)) # sum of squares 285 >>> xvec = [10, 20, 30] >>> yvec = [7, 5, 3] >>> sum(x*y for x,y in zip(xvec, yvec)) # dot product 260 >>> from math import pi, sin >>> sine_table = dict((x, sin(x*pi/180)) for x in range(0, 91)) >>> unique_words = set(word for line in page for word in line.split()) >>> valedictorian = max((student.gpa, student.name) for student in graduates) >>> data = 'golf' >>> list(data[i] for i in range(len(data)-1,-1,-1)) ['f', 'l', 'o', 'g'] 10. Giới thiệu sơ về bộ thư viện chuẩn10.1 Giao tiếp với hệ thống
>>> import os >>> os.system('time 0:02') 0 >>> os.getcwd() # Return the current working directory 'C:\\Python24' >>> os.chdir('/server/accesslogs') Nhớ dùng kiểu lệnh >>> import os >>> dir(os) Đối với các công việc quản lý file và thư mục thông thường, mô-đun >>> import shutil >>> shutil.copyfile('data.db', 'archive.db') >>> shutil.move('/build/executables', 'installdir') 10.2 Ký tự thay thế tập tin
>>> import glob >>> glob.glob('*.py') ['primes.py', 'random.py', 'quote.py'] 10.3 Thông số dòng lệnhCác kịch bản phổ dụng thường phải xử lý
các tham số dòng lệnh. Các tham số này được lưu thành một danh sách ở mô-đun sys trong thuộc tính >>> import sys >>> print sys.argv ['demo.py', 'one', 'two', 'three']
10.4 Chuyển hướng luồng ra và kết thúc chương trình
>>> sys.stderr.write('Warning, log file not found starting a new one\n') Warning, log file not found starting a new one Cách thoát khỏi một kịch bản một cách trực tiếp nhất là dùng 10.5 Khớp mẫu chuỗi
>>> import re >>> re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest') ['foot', 'fell', 'fastest'] >>> re.sub(r'(\b[a-z]+) ', r'', 'cat in the the hat') 'cat in the hat' Đối với các chức năng xử lý chuỗi cơ bản thì các phương thức của đối tượng chuỗi được ưa chuộng hơn bởi chúng dễ đọc và dễ gỡ rối hơn: >>> 'tea for too'.replace('too', 'two') 'tea for two' 10.6 Toán học
>>> import math >>> math.cos(math.pi / 4.0) 0.70710678118654757 >>> math.log(1024, 2) 10.0
>>> import random >>> random.choice(['apple', 'pear', 'banana']) 'apple' >>> random.sample(xrange(100), 10) # sampling without replacement [30, 83, 16, 4, 8, 81, 41, 50, 18, 33] >>> random.random() # random float 0.17970987693706186 >>> random.randrange(6) # random integer chosen from range(6) 4 10.7 Truy cập internetPython cung
cấp một vài mô-đun khác nhau cho việc truy cập internet và xử lý các giao thức internet. Hai mô-đun đơn giản nhất là >>> import urllib2 >>> for line in urllib2.urlopen('http://tycho.usno.navy.mil/cgi-bin/timer.pl'): ... if 'EST' in line or 'EDT' in line: # look for Eastern Time ... print line 10.8 Ngày và giờ
# dates are easily constructed and formatted >>> from datetime import date >>> now = date.today() >>> now datetime.date(2003, 12, 2) >>> now.strftime("%m-%d-%y. %d %b %Y is a %A on the %d day of %B.") '12-02-03. 02 Dec 2003 is a Tuesday on the 02 day of December.' # dates support calendar arithmetic >>> birthday = date(1964, 7, 31) >>> age = now - birthday >>> age.days 14368 10.9 Nén dữ liệuPython cung cấp một số mô-đun hỗ trợ trực tiếp các định dạng nén và lưu trữ dữ liệu phổ biến như: zlib, gzip, bz2, zipfile, và tarfile. >>> import zlib >>> s = 'witch which has which witches wrist watch' >>> len(s) 41 >>> t = zlib.compress(s) >>> len(t) 37 >>> zlib.decompress(t) 'witch which has which witches wrist watch' >>> zlib.crc32(s) 226805979 10.10 Đo lường hiệu suấtMột vài người dùng Python rất quan tâm đến việc tìm hiểu sự khác bệt về hiệu năng giữa các phương án
khác nhau của cùng một vấn đề. Python cung cấp một công cụ đo đạc để thỏa mãn nhu cầu này. >>> from timeit import Timer >>> Timer('t=a; a=b; b=t', 'a=1; b=2').timeit() 0.57535828626024577 >>> Timer('a,b = b,a', 'a=1; b=2').timeit() 0.54962537085770791 So sánh với độ phân biệt về thời gian và sự chính xác cao của 10.11 Quản lý chất lượngMột phương pháp để phát triển phần mềm chất lượng cao là viết các hàm kiểm tra cho từng hàm khi viết các hàm và chạy các hàm kiểm tra một cách thường xuyên trong quá trình phát triển phần mềm. def average(values): """Computes the arithmetic mean of a list of numbers. >>> print average([20, 30, 70]) 40.0 """ return sum(values, 0.0) / len(values) import doctest doctest.testmod() # automatically validate the embedded tests unittest (mô-đun) không dễ dùng như mô-đun doctest, nhưng nó hỗ trợ các hàm kiểm tra toàn diện hơn và lưu giữ chúng trong một tập tin riêng biệt: import unittest class TestStatisticalFunctions(unittest.TestCase): def test_average(self): self.assertEqual(average([20, 30, 70]), 40.0) self.assertEqual(round(average([1, 5, 7]), 1), 4.3) self.assertRaises(ZeroDivisionError, average, []) self.assertRaises(TypeError, average, 20, 30, 70) unittest.main() # Calling from the command line invokes all tests 10.12 Kèm cả pinPython được gắn với ý tưởng “kèm pin”. Điều này được thể hiện bởi các tính năng mạnh mẽ và đa dạng của các gói lớn hơn của nó. Ví dụ như:
11. Giới thiệu sơ về bộ thư viện chuẩn – Phần IIBài giới thiệu thứ hai này nói về các mô-đun chuyên sâu nhằm đáp ứng các tác vụ lập trình chuyên nghiệp. Các mô-đun này ít khi xuất hiện ở các kịch bản nhỏ. 11.1 Định dạng rarepr (mô-đun)cung cấp một phiên bản repr() đã được tùy biến để hiển thị vắn tắt các đối tượng chứa (container) lớn hoặc lồng nhau nhiều mức: >>> import repr >>> repr.repr(set('supercalifragilisticexpialidocious')) "set(['a', 'c', 'd', 'e', 'f', 'g',...])" pprint (mô-đun) hỗ trợ việc kiểm soát việc in các đối tượng sẵn có hoặc các đối tượng do người dùng định nghĩa một cách tinh vi hơn theo một phương thúc mà rình thông dịch có thể hiểu được. Khi kết quả hiển thị ngắn hơn một dòng thì “pretty printer” sẽ thêm các dấu xuống dòng và dấu thụt vào đầu dòng khiến cho cấu trúc dữ liệu được thể hiện rõ rệt hơn: >>> import pprint >>> t = [[[['black', 'cyan'], 'white', ['green', 'red']], [['magenta', ... 'yellow'], 'blue']]] ... >>> pprint.pprint(t, width=30) [[[['black', 'cyan'], 'white', ['green', 'red']], [['magenta', 'yellow'], 'blue']]] textwrap (mô-đun) định dạng đoạn văn bản sao cho vừa với độ rộng của màn hình: >>> import textwrap >>> doc = """The wrap() method is just like fill() except that it returns ... a list of strings instead of one big string with newlines to separate ... the wrapped lines.""" ... >>> print textwrap.fill(doc, width=40) The wrap() method is just like fill() except that it returns a list of strings instead of one big string with newlines to separate the wrapped lines. locale (mô-đun) sử dụng một cơ sở dữ liệu các định dạng dữ liệu dựa trên đặc điểm của từng khu vực. Hàm định dạng của locale có thuộc tính tạo nhóm, cho phép định dạng trực tiếp các con số với các dấu phân chia nhóm: >>> import locale >>> locale.setlocale(locale.LC_ALL, 'English_United States.1252') 'English_United States.1252' >>> conv = locale.localeconv() # get a mapping of conventions >>> x = 1234567.8 >>> locale.format("%d", x, grouping=True) '1,234,567' >>> locale.format("%s%.*f", (conv['currency_symbol'], ... conv['frac_digits'], x), grouping=True) '$1,234,567.80' 11.2 Tạo mẫustring (mô-đun) cung cấp một lớp Template với một cú pháp đơn giản,
có thể dễ dàng thay đổi bởi người dùng. Điều này cho phép người dùng có thể tùy biến trình ứng dụng mà không phải thay đổi nó. >>> from string import Template >>> t = Template('${village}folk send $$10 to $cause.') >>> t.substitute(village='Nottingham', cause='the ditch fund') 'Nottinghamfolk send $10 to the ditch fund.'
>>> t = Template('Return the $item to $owner.') >>> d = dict(item='unladen swallow') >>> t.substitute(d) Traceback (most recent call last): ... KeyError: 'owner' >>> t.safe_substitute(d) 'Return the unladen swallow to $owner.' Các lớp con của Template có thể định nghĩa một phần tử phân chia tùy biến. Ví dụ một ứng dụng đổi tên ảnh hàng loạt của một trình duyệt ảnh có thể sử dụng dấu phần trăm để làm các biến giữ chỗ ngày tháng, số thứ tự ảnh, hay định dạng ảnh: >>> import time, os.path >>> photofiles = ['img_1074.jpg', 'img_1076.jpg', 'img_1077.jpg'] >>> class BatchRename(Template): ... delimiter = '%' >>> fmt = raw_input('Enter rename style (%d-date %n-seqnum %f-format): ') Enter rename style (%d-date %n-seqnum %f-format): Ashley_%n%f >>> t = BatchRename(fmt) >>> date = time.strftime('%d%b%y') >>> for i, filename in enumerate(photofiles): ... base, ext = os.path.splitext(filename) ... newname = t.substitute(d=date, n=i, f=ext) ... print '%s --> %s' % (filename, newname) img_1074.jpg --> Ashley_0.jpg img_1076.jpg --> Ashley_1.jpg img_1077.jpg --> Ashley_2.jpg Một ứng dụng khác của tạo mẫu là việc tách biệt lô-gíc chương trình ra khỏi các chi tiết về các định dạng đầu ra khác nhau. Điều này giúp cho việc thay thế các khuôn mẫu tùy biến cho các tập tin XML, các báo cáo bằng văn bản thông thường và các báo cáo bằng HTML. 11.3 Làm việc với bản ghi dữ liệu nhị phânstruct (mô-đun) cung cấp các hàm import struct data = open('myfile.zip', 'rb').read() start = 0 for i in range(3): # show the first 3 file headers start += 14 fields = struct.unpack('LLLHH', data[start:start+16]) crc32, comp_size, uncomp_size, filenamesize, extra_size = fields start += 16 filename = data[start:start+filenamesize] start += filenamesize extra = data[start:start+extra_size] print filename, hex(crc32), comp_size, uncomp_size start += extra_size + comp_size # skip to the next header 11.4 Đa luồngPhân luồng là kỹ thuật phân tách các tác vụ khác nhau của một chương trình khi chúng không bị ràng buộc trật tự với nhau. Các luồng được sử dụng để tăng tính đáp ứng của các chương trình ứng dụng đòi hỏi việc
nhập liệu từ người dùng diễn ra cùng lúc với các tiến trình nền khác. Một trường hợp tương tự là việc chạy các tác vụ vào ra song song với các tác vụ tính toán ở một luồng khác. import threading, zipfile class AsyncZip(threading.Thread): def __init__(self, infile, outfile): threading.Thread.__init__(self) self.infile = infile self.outfile = outfile def run(self): f = zipfile.ZipFile(self.outfile, 'w', zipfile.ZIP_DEFLATED) f.write(self.infile) f.close() print 'Finished background zip of: ', self.infile background = AsyncZip('mydata.txt', 'myarchive.zip') background.start() print 'The main program continues to run in foreground.' background.join() # Wait for the background task to finish print 'Main program waited until background was done.' Khó khăn lớn nhất của các chương trình ứng dụng đa luồng là việc điều phối các luồng phải chia sẻ dữ liệu hay các tài nguyên khác. Về mặt này, mô-đun 11.5 Nhật kýlogging (mô-đun) cung cấp một hệ thống ghi nhật ký (logging) linh hoạt và có đầy đủ các tính năng. Trong trường hợp đơn giản nhất, một thông điệp nhật ký được gửi tới một tập tin hay tới sys.stderr: import logging logging.debug('Debugging information') logging.info('Informational message') logging.warning('Warning:config file %s not found', 'server.conf') logging.error('Error occurred') logging.critical('Critical error -- shutting down') Đoạn mã trên sẽ cho kết quả sau: WARNING:root:Warning:config file server.conf not found ERROR:root:Error occurred CRITICAL:root:Critical error -- shutting down Theo mặc định, các thông điệp chứa thông tin dành cho việc gỡ rối bị chặn lại và đầu ra được gửi tới kênh báo lỗi
chuẩn. Các thông điệp này còn có thể được chuyển tiếp tới thư điện tử, gói tin, socket hay máy chủ HTTP. Các bộ lọc có thể chọn các cơ chế chuyển tiếp tùy theo mức độ ưu tiên của thông điệp: DEBUG, INFO, WARNING, ERROR, và CRITICAL. 11.6 Tham chiếu yếuPython
hỗ trợ việc quản lý bộ nhớ một cách tự động (bao gồm việc đếm tham chiếu với hầu hết các đối tượng và việc thu dọn rác). Vùng nhớ được giải phóng nhanh chóng sau khi tham chiếu cuối cùng đến nó kết thúc. >>> import weakref, gc >>> class A: ... def __init__(self, value): ... self.value = value ... def __repr__(self): ... return str(self.value) ... >>> a = A(10) # create a reference >>> d = weakref.WeakValueDictionary() >>> d['primary'] = a # does not create a reference >>> d['primary'] # fetch the object if it is still alive 10 >>> del a # remove the one reference >>> gc.collect() # run garbage collection right away 0 >>> d['primary'] # entry was automatically removed Traceback (most recent call last): File " 11.7 Công cụ làm việc với danh sáchKiểu danh sách sẵn có của Python có thể đáp
ứng được nhu cầu về nhiều kiểu cấu trúc dữ liệu khác nhau. Tuy vậy chúng ta đôi khi cần tới các kiểu cấu trúc khác, tùy thuộc vào các mục tiêu cụ thể về hiệu năng. >>> from array import array >>> a = array('H', [4000, 10, 700, 22222]) >>> sum(a) 26932 >>> a[1:3] array('H', [10, 700]) collections (mô-đun) cung cấp đối tượng deque() giống như một danh sách nhưng có các thao tác thêm vào và lấy ra đầu bên trái nhanh hơn, nhưng việc tìm kiếm ở giữa thì lại chậm hơn. Các đối tượng này thích hợp cho việc cài đặt các hàng đợi và tìm kiếm cây theo chiều rộng: >>> from collections import deque >>> d = deque(["task1", "task2", "task3"]) >>> d.append("task4") >>> print "Handling", d.popleft() Handling task1 unsearched = deque([starting_node]) def breadth_first_search(unsearched): node = unsearched.popleft() for m in gen_moves(node): if is_goal(m): return m unsearched.append(m) Ngoài các cấu trúc thay thế cho danh sách, thư viện chuẩn còn cung cấp các công cụ như mô-đun bisect chứa các hàm thao tác trên danh sách đã được sắp xếp: >>> import bisect >>> scores = [(100, 'perl'), (200, 'tcl'), (400, 'lua'), (500, 'python')] >>> bisect.insort(scores, (300, 'ruby')) >>> scores [(100, 'perl'), (200, 'tcl'), (300, 'ruby'), (400, 'lua'), (500, 'python')] heapq (mô-đun) cung cấp các hàm để cài đặt đống (heap) dựa trên các danh sách thông thường. Phần tử có giá trị thấp nhất luôn được giữ ở vị trí đầu tiên. Hàm này rất có ích trong các trình ứng dụng đòi hỏi việc truy cập tới phần tử nhỏ nhất mà không cần phải sắp xếp lại toàn bộ danh sách: >>> from heapq import heapify, heappop, heappush >>> data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0] >>> heapify(data) # rearrange the list into heap order >>> heappush(data, -5) # add a new entry >>> [heappop(data) for i in range(3)] # fetch the three smallest entries [-5, 0, 1] 11.8 Số học dấu chấm động thập phândecimal (mô-đun) cung cấp kiểu dữ liệu >>> from decimal import * >>> Decimal('0.70') * Decimal('1.05') Decimal("0.7350") >>>.70 * 1.05 0.73499999999999999
>>> Decimal('1.00') % Decimal('.10') Decimal("0.00") >>> 1.00 % 0.10 0.09999999999999995 >>> sum([Decimal('0.1')]*10) == Decimal('1.0') True >>> sum([0.1]*10) == 1.0 False decimal (mô-đun) cung cấp các phép toán với độ chính xác cao, tùy thuộc vào đòi hỏi của người dùng: >>> getcontext().prec = 36 >>> Decimal(1) / Decimal(7) Decimal("0.142857142857142857142857142857142857") 12. Tiếp theo?Đọc xong bài chỉ dẫn này có lẽ đã làm tăng thêm sự thích thú của bạn với ngôn ngữ Python — và bạn cũng muốn nhanh chóng áp dụng Python để giải quyết các vấn đề trong đời sống. Thế bây giờ bạn nên học
tiếp từ đâu?
Bạn nên duyệt qua cẩm nang này vì nó cung cấp tài liệu tham khảo đầy đủ (dù là ngắn gọn) về các kiểu, hàm, và các mô-đun trong bộ thư viện chuẩn. Bộ phân phối Python chuẩn có rất nhiều mã bổ sung. Có những mô-đun để đọc hộp thư Unix, lấy tài liệu từ HTTP, sinh số ngẫu nhiên, phân tích thông số dòng lệnh, viết các ứng dụng CGI, nén dữ liệu, và rất nhiều tác vụ khác. Lướt qua Tham khảo thư viện sẽ cho bạn biết những gì đang có.
Các tài nguyên Python khác:
Để hỏi các câu hỏi liên quan tới Python và thông báo lỗi, bạn có thể gửi với nhóm tin comp.lang.python, hoặc gửi chúng tới danh sách thư tín . Nhóm tin và danh sách thư tín được nối chung với nhau, nên các tin gửi ở nơi này sẽ tự động có mặt ở nơi kia. Có khoảng 120 bài gửi một ngày (cao nhất là vài trăm), hỏi (và trả lời) câu hỏi, đề xuất các tính năng mới, và thông báo các mô-đun mới. Trước khi gửi, hãy nhớ xem qua danh sách Các câu hỏi thường hỏi (Frequently Asked Question) (còn được gọi là FAQ), hoặc xem qua thư mục Misc/ của bản phân phối nguồn Python. Kho lưu trữ nhóm tin có ở http://mail.python.org/pipermail/. FAQ trả lời nhiều câu hỏi hay gặp thường xuyên, và có thể câu hỏi của bạn cũng có ở trong này. Glossary
[1]Gói GNU Readline có một lỗi có thể ngăn cản điều này. |