Giới thiệu về ngôn ngữ lập trình Python

Bài viết này giới thiệu sơ lược về ngôn ngữ lập trình python, giới thiệu tài liệu về ngôn ngữ python do tác giả dịch từ tiếng Nga sang tiếng Việt và nhiều tài liệu sưu tầm khác … (Bài này được đăng trên blog cá nhân của tác giả từ nhiều năm về trước. Bạn đọc quan tâm có thể xem link gốc ở đây)

python_icon

Là một lập trình viên hoặc đơn giản là một người yêu thích lập trình ngôn ngữ, có lẽ bạn không ít nhiều nghe nói đến python. Ngôn ngữ chính là phương tiện giao tiếp liên kết giữa các thành viên trong một cộng đồng xã hội, có rất nhiều ngôn ngữ khác nhau, có nhiều tiếng nói khác nhau, để hiểu được một thành viên nào đó, chúng ta cần biết đến ngôn ngữ của họ. Đối với ngôn ngữ lập trình cũng thế, để tương tác được với môi trường làm việc, chúng ta phải hiểu sâu sắc về nó. Hôm nay tôi muốn trao đổi với các bạn về một ngôn ngữ lập trình bậc cao, hướng đối tượng, mạnh, mới, được đánh giá là có tương lai rất rạng rỡ, đó chính là con trăn khổng lồ – python hung hãn, hoặc là mạnh mẽ, hoặc là thân thiện.

Bài viết của tôi dựa trên những quan điểm nhìn nhận từ chiều hướng cá nhân qua một thời gian học tập và tìm hiểu. Kèm theo đó tôi muốn giới thiệu một số tài liệu nhằm giúp đỡ cho việc học tập python, trong đó có tài liệu nguyên văn tiếng nước ngoài, chỉ dẫn một số tài liệu sưu tầm, và có tài liệu tiếng Việt do tôi tự dịch từ tiếng Nga trong quá trình học tập. Môi trường thử nghiệm để dịch python của tôi là linux/fedora 10 (từ khi fedora 10 là lastest version trong dòng fedora) …

Python là một ngôn ngữ lập trình thông dịch do Guido van Rossum tạo ra năm 1990. Python hoàn toàn tạo kiểu động và dùng cơ chế cấp phát bộ nhớ tự động; do vậy nó tương tự như Perl, Ruby, Scheme, Smalltalk, và Tcl. Python được phát triển trong một dự án mã mở, do tổ chức phi lợi nhuận Python Software Foundation quản lý.
Theo đánh giá của Eric S. Raymond, Python là ngôn ngữ có hình thức rất sáng sủa, cấu trúc rõ ràng, thuận tiện cho người mới học lập trình. Cấu trúc của Python còn cho phép người sử dụng viết mã lệnh với số lần gõ phím tối thiểu, như nhận định của chính Guido van Rossum trong một bài phỏng vấn ông.

Ban đầu, Python được phát triển để chạy trên nền Unix. Nhưng rồi theo thời gian, nó đã “bành trướng” sang mọi hệ điều hành từ MS-DOS đến Mac OS, OS/2, Windows, Linux và các hệ điều hành khác thuộc họ Unix. Mặc dù sự phát triển của Python có sự đóng góp của rất nhiều cá nhân, nhưng Guido van Rossum hiện nay vẫn là tác giả chủ yếu của Python. Ông giữ vai trò chủ chốt trong việc quyết định hướng phát triển của Python

PHẦN I – TỔNG QUAN VỀ PYTHON

  • Giới thiệu python
  • Lịch sử phát triển
  • Sơ lược về đặc điểm
  • Các phiên bản

PHẦN II – TÌM HIỂU VỀ KIẾN TRÚC LẬP TRÌNH PYTHON

  • Cấu trúc và kỹ thuật làm việc với dữ liệu trong Python
  • Cú pháp và các cấu trúc lập trình cơ bản trong Python
  • Hàm trong Python
  • Lớp trong Python
  • Các kỹ thuật vềmodule
  • Thao tác vào và ra
  • Phạm vi (scope) và không gian tên (name space) trong Python
  • Các kỹ thuật đặc biệt trong Python
  • Lập trình giao diện

Phần III – Trình biên dịch cho Python
Trong hầu hết các Linux OS thì trình dịch Python được tích hợp. Nếu chưa được tích hợp lúc cài đặt, các bạn có thể tải các gói(Package) về để cài đặt. Khi dịch Python chúng ta gõ lệnh python và màn hình console sẽ hiện ra, nó là một trình thông dịch ở dạng cửa sổ dòng lệnh.

Trên Windows có hỗ trợ nhiều trình dịch khác nhau, tôi đã dùng thử Python 2.6 for Windows và thấy khá thú vị(tuy nhiên không bằng dùng trong Linux). Các bạn có thể download các phiên bản khác nhau của nó ở đây về để cài đặt. Việc cài đặt rất đơn giản, nếu có vấn đề gì trong việc cài đặt hoặc vấn đề biên dịch xin để lại thông tin trong phần comment, tôi sẵn sàng giúp đỡ các bạn!

Bài viết tuy còn sơ sài nhưng tôi hi vọng rằng các bạn sẽ tìm được đôi điều thú vị và tạo cho mình một đam mê với ngôn ngữ Python! Chúc các bạn vui vẻ và thành công!

Phần I – Tổng quan về Python
I.1. Giới thiệu về Python

Python là một ngôn ngữ lập trình hướng đối tượng rất thông dụng dùng để viết các tiện ích hệ thống và các đoạn mã trên Internet. Nó cũng được sử dụng như ngôn ngữ kết dính đóng vai trò tích hợp C và C++. Được tạo ra bởi Guido van Rossum tại Amsterdamnăm 1990. Python hoàn toàn tạo kiểu động và dùng cơ chế cấp phát bộ nhớ tự động; do vậy nó gần giống như Perl, Ruby, Scheme, Smalltalk, và Tcl. Python được phát triển trong một dự án mã mở, do tổ chức phi lợi nhuận Python Software Foundation quản lý. Python bản 2.4.3 được phát hành vào 29 tháng 3, 2006. Bản tiếp theo là Python 2.5 release candidate 2.

Gần đây nhất, đầu tháng 8/2006 Microsoft đã cho ra mắt bản phân phối thử nghiệm IronPython 1.0, vừa tích hợp tốt với .Net Framework, vừa hoàn toàn kế thừa ngôn ngữ Python. IronPython còn tận dụng CLI ( nền tảng ngôn ngữ chung ) để đạt hiệu năng cao, chạy nhanh hơn 1.5 lần so với Python nền C thông thường dựa trên thang đo benchmark.

Python là ngôn ngữ có hình thức rất sáng sủa, cấu trúc rõ ràng, thuận tiện cho người mới học lập trình. Cấu trúc của Python còn cho phép người sử dụng viết mã lệnh với số lần gõ phím tối thiểu.

Ban đầu, Python được phát triển để chạy trên nền Unix. Nhưng rồi theo thời gian, nó đã “bành trướng” sang mọi hệ điều hành từ DOS đến Mac OS, OS/2, Windows, Linux và các hệ điều hành khác thuộc họ Unix. Mặc dù sự phát triển của Python có sự đóng góp của rất nhiều cá nhân, nhưng Guido van Rossum hiện nay vẫn là tác giả chủ yếu của Python. Ông giữ vai trò chủ chốt trong việc quyết định hướng phát triển của Python.

I.2. Lịch sử phát triển của Python.

Sự phát triển Python đến nay có thể chia làm các giai đoạn:

Python 1: bao gồm các bản phát hành 1.x. Giai đoạn này, kéo dài từ đầu đến cuối thập niên 1990. Từ năm 1990 đến 1995, Guido làm việc tại CWI (Centrum voor Wiskunde en Informatica – Trung tâm Toán-Tin học) tại Amsterdam, Hà Lan. Vì nguyên nhân này, các phiên bản Python đầu tiên đều do CWI phát hành. Phiên bản cuối cùng phát hành tại CWI là 1.2.
Vào năm 1995, Guido chuyển sang Corporation for National Research Initiatives (CNRI) ở Reston, Virginia. Tại đây, ông phát hành một số phiên bản khác. Python 1.6 là phiên bản cuối cùng phát hành tại CNRI.
Sau bản phát hành 1.6, Guido rời bỏ CNRI để làm việc với các lập trình viên chuyên viết phần mềm thương mại. Tại đây, ông có ý tưởng sử dụng Python với các phần mềm tuân theo chuẩn GPL. Sau đó, CNRI và Free Software Foundation (FSF) đã cùng nhau hợp tác để làm bản quyền Python phù hợp với GPL. Cùng năm đó, Guido được nhận giải thưởng FSF Award for the Advancement of Free Software.
Phiên bản 1.6.1 ra đời sau đó là phiên bản đâu tiền tuân theo bản quyền GPL. Tuy nhiên, bản này hoàn toàn giống bản 1.6, trừ một số sửa lỗi cần thiết.
Python 2: vào năm 2000, Guido và nhóm phát triển Python dời đến BeOpen.com và thành lập BeOpen PythonLabs team. Phiên bản Python 2.0 được phát hành tại đây. Sau khi phát hành Python 2.0, Guido và các thành viên PythonLabs gia nhập Digital Creations.
Python 2.1 ra đời kế thừa từ Python 1.6.1 và Python 2.0. Bản quyền của phiên bản này được đổi thành Python Software Foundation License. Từ thời điểm này trở đi, Python thuộc sở hữu của Python Software Foundation (PSF), một tổ chức phi lợi nhuận được thành lập theo mẫu Apache Software Foundation.

· Python 3: Về sự phát triển của Python trong tương lai, các nhà phát triển vẫn đang thảo luận về phiên bản mới: Python 3.0 (dự án gọi là Python 3000 hoặc Py3K). Dự kiến, dòng 3.x sẽ không hoàn toàn tương thích với dòng 2.x. Nhóm phát triển cho biết sẽ lấp những chỗ hở của ngôn ngữ. Nguyên tắc chủ đạo để phát triển Python 3.x là “bỏ cách làm việc cũ nhằm hạn chế trùng lặp về mặt chức năng của Python”. Tuy nhiên, cho đến nay vẫn chưa có kế hoạch cụ thể cho phát triển Python 3.

I.3. Sơ lược về đặc điểm của Python:

Python được thiết kế để trở thành một ngôn ngữ dễ học, mã nguồn dễ đọc, bố cục trực quan, dễ hiểu, thể hiện qua các điểm sau:

1. Từ khoá:

Python tăng cường sử dụng từ khóa tiếng Anh, hạn chế các kí hiệu và cấu trúc cú pháp so với các ngôn ngữ khác. Python là một ngôn ngữ phân biệt kiểu chữ. Như C/C++, các từ khóa của Python đều ở dạng chữ thường. Dưới đây là hệ thống từ khóa chuẩn:

and del from not while

as elif global or with

assert else if pass yield

break except import print

class exec in raise

continue finally is return

def for lambda try

2. Khối lệnh:

Python, có một cách rất đặc biệt để tạo khối lệnh, đó là thụt các câu lệnh trong khối vào sâu hơn (về bên phải) so với các câu lệnh của khối lệnh cha chứa nó.Ví dụ giả sử có đoạn mã sau trong C/C++:

#include

//…

delta = b * b – 4 * a * c;

if (delta > 0)

{

// Khối lệnh mới bắt đầu từ kí tự { đến }

x1 = (- b + sqrt(delta)) / (2 * a);

x2 = (- b – sqrt(delta)) / (2 * a);

printf(“Phuong trinh co hai nghiem phan biet:\n”);

printf(“x1 = %f; x2 = %f”, x1, x2);

}

Đoạn mã trên có thể được viết lại bằng Python như sau:

import math

#…

delta = b * b – 4 * a * c

if delta > 0:

# Khối lệnh mới, thụt vào đầu dòng

x1 = (- b + math.sqrt(delta)) / (2 * a)

x2 = (- b – math.sqrt(delta)) / (2 * a)

print “Phuong trinh co hai nghiem phan biet:”

print “x1 = “, x1, “; “, “x2 = “, x2

Ta có thể sử dụng tab hoặc khoảng trống để thụt các câu lệnh vào.

3. Khả năng mở rộng:

Python có thể được mở rộng: nếu ta biết sử dụng C, ta có thể dễ dàng viết và tích hợp vào Python nhiều hàm tùy theo nhu cầu. Các hàm này sẽ trở thành hàm xây dựng sẵn (built-in) của Python. Ta cũng có thể mở rộng chức năng của trình thông dịch, hoặc liên kết các chương trình Python với các thư viện chỉ ở dạng nhị phân (như các thư viện đồ họa do nhà sản xuất thiết bị cung cấp). Hơn thế nữa, ta cũng có thể liên kết trình thông dịch của Python với các ứng dụng viết từ C và sử dụng nó như là một mở rộng hoặc một ngôn ngữ dòng lệnh phụ trợ cho ứng dụng đó.
4. Trình thông dịch

Python là một ngôn ngữ lập trình dạng thông dịch. Ưu điểm của thông dịch là giúp ta tiết kiệm thời gian phát triển ứng dụng vì không cần phải thực hiện biên dịch và liên kết. Trình thông dịch có thể được sử dụng để chạy file script, hoặc cũng có thể được sử dụng một cách tương tác. Ở chế độ tương tác, trình thông dịch Python tương tự shell của các hệ điều hành họ Unix, tại đó, ta có thể nhập vào một biểu thức tại một thời điểm rồi enter, và kết quả thực thi sẽ được hiển thị ngay lập tức. Đặc điểm này rất hữu ích cho người mới học, giúp họ nghiên cứu tính năng của ngôn ngữ; hoặc để các lập trình viên chạy thử mã trong suốt quá trình phát triển phần mềm. Ngoài ra, nó cũng có thể được sử dụng như là một máy tính.

5. Lệnh và cấu trúc điều khiển:

Mỗi câu lệnh trong Python nằm trên một dòng mã nguồn. Ta không cần phải kết thúc câu lệnh bằng bất kì kí tự gì. Cũng như các ngôn ngữ khác, Python cũng có các cấu trúc điều khiển. Chúng bao gồm:

Cấu trúc rẽ nhánh: cấu trúc if (có thể sử dụng thêm elif hoặc else), dùng để thực thi có điều kiện một khối mã cụ thể.

Cấu trúc lặp, bao gồm:

Lệnh while: chạy một khối mã cụ thể cho đến khi điều kiện lặp có giá trị false.

Vòng lặp for: lặp qua từng phần tử của một dãy, mỗi phần tử sẽ được đưa vào biến cục bộ để sử dụng với khối mã trong vòng lặp.

Python cũng có từ khóa class dùng để khai báo lớp (sử dụng trong lập trình hướng đối tượng) và lệnh def dùng để định nghĩa hàm.

6. Hệ thống kiểu dữ liệu:

Python sử dụng hệ thống kiểu duck typing, còn gọi là latent typing (hàm nghĩa: ngầm). Có nghĩa là, Python không kiểm tra các ràng buộc về kiểu dữ liệu tại thời điểm dịch, mà là tại thời điểm thực thi. Khi thực thi, nếu một thao tác trên một đối tượng bị thất bại, thì có nghĩa là, đối tượng đó không sử dụng một kiểu thích hợp. Python cũng là một ngôn ngữ định kiểu mạnh. Nó cấm mọi thao tác không hợp lệ, ví dụ cộng một con số vào chuỗi. Sử dụng Python, ta không cần phải khai báo biến. Biến được xem là đã khai báo nếu nó được gán một giá trị lần đầu tiên. Căn cứ vào mỗi lần gán, Python sẽ tự động xác định kiểu dữ liệu của biến. Python có một số kiểu dữ liệu thông dụng sau:

int, long: số nguyên

float: số thực

complex: số phức

list: chuỗi có thể thay đổi

tuple: chuỗi không thể thay đổi

str: chuỗi kí tự không thể thay đổi

dict: từ điển

set: một tập không xếp theo thứ tự, ở đó, mỗi phần tử chỉ xuất hiện một lần.

Ngoài ra, Python còn có nhiều kiểu dữ liệu khác.

7. Module ( khối chương trình )

Python cho phép chia chương trình thành modules để có thể sử dụng lại trong các chương trình khác. Nó cũng có sẵn một tập hợp các modules chuẩn mà ta có thể sử dụng lại trong chương trình của ta. Các thư viện này cung cấp nhiều thứ, như file I/O, các lời gọi hệ thống, sockets,…

8. Đa năng:

Python là một ngôn ngữ lập trình đơn giản nhưng rất hiệu quả. So với Unix shell, Python hỗ trợ các chương trình lớn hơn và cung cấp nhiều cấu trúc hơn. So với C, Python cung cấp nhiều cơ chế kiểm tra lỗi hơn. Vì các lí do đó, Python là một ngôn ngữ lập trình cấp rất cao. Nó cũng có sẵn nhiều kiểu dữ liệu cấp cao, ví dụ như các mảng linh hoạt (flexible arrays) ( ) và từ điển (dictionaries) mà ta phải mất nhiều thời gian để hiện thực trên C. Python cũng thích hợp với các chương trình lớn hơn cả Awk và Perl. Python cũng được sử dụng để lập trình Web. Nó có thể được sử dụng như là một ngôn ngữ kịch bản. Python được thiết kế để có thể nhúng và phục vụ như là một ngôn ngữ kịch bản để tuỳ biến và mở rộng các ứng dụng lớn hơn. Được tích hợp sẵn nhiều công cụ và có một thư viện chuẩn phong phú, Python cho phép người dùng dễ dàng tạo ra các dịch vụ Web, sử dụng các thành phần COM hay CORBA ( ). Nó hỗ trợ các định dạng email, dữ liệu Internet, HTML, XML và các ngôn ngữ đánh dấu khác. Python cũng ứng dụng tất cả các giao thức Internet thông dụng như HTTP, FTP,… Python cung cấp giao tiếp đến hầu hết cơ sở dữ liệu, có khả năng xử lí văn bản, tài liệu hiệu quả, và có thể làm việc tốt với các công nghệ Web khác. Python cũng đặc biệt hiệu quả cho lập trình tính toán khoa học qua các công cụ Python Imaging Library, VTK, MayaVi 3D Visualization Toolkits, Numeric Python, ScientificPython,… Python cũng có thể được sử dụng để phát triển các ứng dụng Desktop. Người dùng có thể dùng wxPython, PyQt, PyGtk để phát triển các ứng dụng giao diện đồ họa (GUI) chất lượng cao. Python có thể hỗ trợ các GUI frameworks khác như MFC, Carbon, Delphi, X11, Motif, và Tk. Python cũng có sẵn một unit testing framework để tạo ra các các bộ test (test suites).
9. Multiple paradigms (đa biến hóa)

Python là một ngôn ngữ đa biến hóa (multiple paradigms). Có nghĩa là, thay vì ép buộc mọi người phải sử dụng duy nhất một phương pháp lập trình, Python lại cho phép sử dụng nhiều phương pháp lập trình khác nhau: hướng đối tượng, có cấu trúc, chức năng, hoặc chỉ hướng đến một khía cạnh. Python kiểu kiểu động và sử dụng bộ thu gom rác để quản lí bộ nhớ. Một đặc điểm quan trọng nữa của Python là giải pháp tên động, kết nối tên biến và tên phương thức lại với nhau trong suốt thực thi của chương trình.

I.4. Các phiên bản nổi tiếng Python:

CPython

Đây là phiên bản đầu tiên và được duy trì lâu nhất của Python, được viết trong C. Những đặc điểm của ngôn ngữ mới xuất hiện đầu tiên từ đây

Jython

Là phiên bản Python trong môi trường Java. Bản này có thể được sử dụng như là một ngôn ngữ script cho những ứng dụng Java. Nó cũng thường được sử dụng để tạo ra những tests thử nghiệm cho thư viện Java

Python for .NET

Phiên bản này thật ra sử dụng phiên bản Cpython, nhưng nó là một ứng dụng .NET được quản lý, và tạo ra thư viện .NET sẵn dùng. Bản này được xây dựng bởi Brian Lloyd.

IronPython

Là một bản Python tiếp theo của .NET, không giống như Python.NET đây là một bản Python hoàn chỉnh, tạo ra IL, và biên dịch mã Python trực tiếp vào một tập hợp .NET.

PyPy

PyPy được viết trên Python, thậm chí cả việc thông dịch từng byte mã cũng được viết trên Python. Nó sử dụng Cpython như một trình thông dịch cơ sở. Một trong những mục đích của dự án cho ra đời phiên bản này là để khuyến khích sự thử nghiệm bản thân ngôn ngữ này làm cho nó dễ dàng hơn để sửa đổi thông dịch (bởi vì nó được viết trên Python).

PHẦN II – TÌM HIỂU VỀ KIẾN TRÚC LẬP TRÌNH PYTHON

II.1. Cấu trúc và kỹ thuật làm việc với dữ liệu trong Python:

Do Python không có một cú pháp rõ ràng để định nghĩa biến mới, nên chỉ có thể khai báo một biến bằng cách gán giá trị cụ thể cho nó. Biến sẽ tự động được giải phóng khi ra khỏi phạm vi của chương trình sử dụng nó.Các ví dụ ở đây thì >>> là dấu nhắc lệnh của trình thông dịch.

Dưới đây là hệ thống kiểu dữ liệu chuẩn:

– Kiểu None : Kiểu này chỉ có 1 giá trị , sử dụng để diện tả sự vắng mặt của giá trị trong nhiều trường hợp , ví dụ nó được trả về từ hàm mà đã xác định trước sẽ không trả về gì. Giá trị thực của nó là false.

– Kiểu NotImplemented : Kiểu này chỉ có 1 giá trị , chỉ có 1 đối tượng có giá trị này .Đối tượng được truy cập thông qua tên được xây dựng sẵn NotImplemented. Các phương thức số học và so sánh có thể trả về kiểu giá trị này nếu chúng chưa cài đặt hành động cho toán tử được cung cấp.Giá trị thực của nó là true.

– Kiểu Ellipsis : Kiểu này cũng có giá trị 1 đơn , cũng chí có 1 đối tượng có giá trị này . Đối tượng được truy cập thông qua tên được xây dựng sẵn Ellipsis . Nó được sử dụng để chỉ ra sự hiện diện của cú pháp “….” . Giá trị thực của nó là true.

– Kiểu Numbers: Được tạo ra bởi các kí tự số và trả về kết quả bởi phép toán số học hoặc các hàm số học. Đối tượng numbers là bất biến, giá trị của nó không thay đổi kể từ khi được tạo ra. Có những giới hạn về giá trịcủa số trong máy tính.

Python phân biệt giữa số nguyên, số dấu phẩy động, và số phức:

Integers

Có 3 loại số nguyên:

o Plain integers – Biểu diễn các số nguyên trong khoảng -2147483648 đến 2147483647. Với các thao tác dịch và mặt nạ , kiểu số này được giả định là số bù 2 ,32 bit hoặc nhiều hơn.

o Long integer – Biểu diễn một khoảng không giới hạn của số nguyên.

o Boolean – Biểu diễn giá trị true hay false. Đối tượng miêu tả 2 giá trị này gọi là đối tượng logic. Kiểu Booleans là một kiểu con của kiểu Plain Integers, và giá trị của nó giống như 0 và 1

Kiểu số thực floating point numbers, và kiểu số phức complex numbers Để khai báo 1 số thưc chỉ việc gán giá trị của biến cho1 số thực, cũng như vậy đối với số phức:

>>> X = 1.0

>>>Y = 2+3j

Một số phức gồm 2 phần thực và ảo, là 2 số dấu phẩy động. Nó có thểđược lấy thông qua thuộc tính z.real và z.image.

– Kiểu chuỗi String , giá trị của string được đặt trong cặp dấu ‘ hoặc “.

>>>a = ‘abcdefg’

>>>b = “12345678”

-> a[0] = ‘a ‘

b[1] = ‘2’

– Kiểu từ điển Dictionary – định nghĩa một quan hệ 1-1 giữa khoá và giá trị , không thể có khoá trùng nhau trong từ điển.

Ví dụ khai báo một từ điển :

>>> d = {“server”:”mpilgrim”, “database”:”master”}

>>> d

{‘server’: ‘mpilgrim’, ‘database’: ‘master’}

>>> d[“server”]

‘mpilgrim’

>>> d[“database”]

‘master’

>>> d[“mpilgrim”]

Traceback (innermost last):

File “”, line 1, in ?

KeyError: mpilgrim

– Kiểu danh sách List – làm việc như là 1 mảng các đối tượng. Sau đây là các phương thức của List:

append(x): Thêm một thành phần vào cuối của danh sách, tương đương với: a[len(a):] = [x].

extend(L): Mở rộng danh sách bằng cách thêm tất cả các thành phần trong danh sách đã nhận. Tương đương với a[len(a):] = L.

insert(i,x): Chèn một phần tử vào một ví trí đã định. Đối số đầu tiên i là chỉ sổ của phần tử trước chỗ sẽ chèn, vì thế a.insert(0, x) chèn tại vị trí đầu của danh sách, và a.insert( len(a), x) tương đương với a.append(x).

remove(x): Loại bỏ phần tử đầu tiên trong danh sách mà có giá trị là x. Nếu không có phần tử như vậy thì báo lỗi.

pop([i]): Loại bỏ phần tử tại vị trí i trong danh sách, và trả về nó. Nếu không xác định chỉ số, a.pop( ) sẽ loại bỏ và trả về phần tử cuối cùng trong danh sách.

index(x): Trả về chỉ số của phần tử có giá trị x đầu tiên danh sách. Nếu không có phần tử như vậy sẽ xảy ra lỗi.

count(x): Trả về số lần x xuất hiện trong danh sách.

sort( ): Sắp xếp các thành phần của danh sách.

reverse( ): Đảo ngược các phần tử trong danh sách.

Ta xem xét các ví dụ sau:

Khai báo một List như sau

>>> li = [‘a’, ‘b’, ‘mpilgrim’, ‘z’, ‘example’]

li[0] = ‘a’

li[1] = ‘b’

li[3]= ‘z’

Thay đổi nội dung danh sách

>>> li

[‘a’, ‘b’, ‘mpilgrim’, ‘z’, ‘example’]

>>> li.append(“new”)

>>> li

[‘a’, ‘b’, ‘mpilgrim’, ‘z’, ‘example’, ‘new’]

>>> li.insert(2, “new”)

>>> li

[‘a’, ‘b’, ‘new’, ‘mpilgrim’, ‘z’, ‘example’, ‘new’]

>>> li.extend([“two”, “elements”])

>>> li

[‘a’, ‘b’, ‘new’, ‘mpilgrim’, ‘z’, ‘example’, ‘new’, ‘two’, ‘elements’]

Tìm kiếm trong List

>>> li

[‘a’, ‘b’, ‘new’, ‘mpilgrim’, ‘z’, ‘example’, ‘new’, ‘two’, ‘elements’]

>>> li.index(“example”)

5

>>> li.index(“new”)

2

>>> li.index(“c”)

Traceback (innermost last):

File “”, line 1, in ?

ValueError: list.index(x): x not in list

>>> “c” in li

False

Xoá phần tử trong list

>>> li

[‘a’, ‘b’, ‘new’, ‘mpilgrim’, ‘z’, ‘example’, ‘new’, ‘two’, ‘elements’]

>>> li.remove(“z”)

>>> li

[‘a’, ‘b’, ‘new’, ‘mpilgrim’, ‘example’, ‘new’, ‘two’, ‘elements’]

>>> li.remove(“new”)

>>> li

[‘a’, ‘b’, ‘mpilgrim’, ‘example’, ‘new’, ‘two’, ‘elements’]

>>> li.remove(“c”)

Traceback (innermost last):

File “”, line 1, in ?

ValueError: list.remove(x): x not in list

>>> li.pop()

‘elements’

>>> li

[‘a’, ‘b’, ‘mpilgrim’, ‘example’, ‘new’, ‘two’]

Sử dụng các toán tử

>>> li = [‘a’, ‘b’, ‘mpilgrim’]

>>> li = li + [‘example’, ‘new’]

>>> li

[‘a’, ‘b’, ‘mpilgrim’, ‘example’, ‘new’]

>>> li += [‘two’]

>>> li

[‘a’, ‘b’, ‘mpilgrim’, ‘example’, ‘new’, ‘two’]

>>> li = [1, 2] * 3

>>> li

[1, 2, 1, 2, 1, 2]

– Kiểu Tuple. Đây là mộtdanh sách không thay đổi

>>> t = (“a”, “b”, “mpilgrim”, “z”, “example”)

>>> t

(‘a’, ‘b’, ‘mpilgrim’, ‘z’, ‘example’)

>>> t[0]

‘a’

>>> t[−1]

‘example’

>>> t[1:3]

(‘b’, ‘mpilgrim’)

Các phương thức insert,index,append,extend như với list không thể thực hiện được.Tuy nhiên in thì thực hiện được. Tuple nhanh hơn list và được sử dụng khi các phần tửcủa nó là cố định không thay đổi, vídụ như key trong kiểu từ điển.

– Kiểu sets: Một set là một tập không có thứ tự và không có các phần tử trùng lặp. Công dụng cơ bản là để kiểm tra thành viên, và loại trừ các mục lặp. Đối tượng set cũng hỗ trợ các phép toán như: hợp, giao, hiệu, và hiệu đối xứng. Dưới đây là một ví dụ:

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

II.2. Cú pháp và các cấu trúc lập trình cơ bản trong Python:

Phần này sẽ trình bày về cú pháp và các cấu trúc lập trình cơ bản nhất trong Python:
1. Toán tử:
Python sử dụng các toán tử sau:

+ – * /

// (chia làm tròn)

% (phần dư)

** (lũy thừa)

~ (not)

& (and)

| (or)

^ (xor)

<> (right shift)

== (bằng)

=

!= (khác)

2. Chú thích
Trong Python để viết dòng chú thích ta sử dụng dấu #

# dòng chú thích

3. Lệnh gán

tên biến = biểu thức

x = 23.8

y = -x ** 2

z1 = z2 = x + y

loiChao = “Hello!”

i += 1 # tăng biến i thêm 1 đơn vị

4. In giá trị:

print biểu thức

print (7 + 8) / 2.0

print (2 + 3j) * (4 – 6j)

Nội suy chuỗi (string interpolation)

print “Hello %s” %(“world!”)

print “i = %d” %i

print “a = %.2f and b = %.3f” %(a,b)

5. Cấu trúc rẽ nhánh với câu lệnh if:
Có 3 dạng cấu trúc rẽ nhánh:

Dạng 1:

if biểu_thức_đúng:

# lệnh …

Dạng 2:

if biểu_thức_đúng:

# lệnh …

else:

# lệnh …

Dạng 3:

if biểu_thức_đúng:

# lệnh …

elif:

# lệnh …

else:

# lệnh …

Có thể có nhiều cặp elif liên tiếp. Ví dụ:

>>> x = int(raw_input(“Please enter an integer: “))

>>> if x >> # Measure some strings:

… a = [‘cat’, ‘window’, ‘defenestrate’]

>>> for x in a:

… print x, len(x)

cat 3

window 6

defenestrate 12

Vì lí do sử dụng như trên cho nên sẽ không an toàn nếu ta sửa đổi một chuỗi mà đang sử dụng để lặp ( điều này chỉ xảy ra với kiểu chuỗi khả biến). Trong trường hợp cần thay đổi chuỗi ( ví dụ lặp lại những thành phần nào đó) thì phải lặp qua một bản sao của chuỗi ban đầu. Chỉ cần dùng kí tự : để làm điều này:

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

b. Lệnh while:

while biểu_thức_đúng:

# lệnh …

7. Hàm range( ):

Nếu cần lặp qua một chuỗi số, hàm range( ) có thể được sử dụng. Nó tạo ra một danh sách chứa chuỗi các số học:

>>> range(10)

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Điểm kết thúc đã cho không bao giờ là một phần của chuỗi sẽ tạo ra; range(10) tạo ra một danh sách 10 giá trị,giống như chỉ số các thành phần của một chuỗi chiều dài 10. Cũng có thể đặt cho range( ) vị trí bắt đầu, hoặc xác định một bước tăng khác.

>>> 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 chỉ số của một chuỗi, sử dụng kết hợp range( ) và len( ) như dưới đây:

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

8. Các câu lệnh break và continue, và mệnh đề else trong vòng lặp:

Câu lệnh break, giống nhau C, nhảy ra khỏi vòng lặp ngay trước nó mà chứa nó.

Câu lệnh continue, cũng kế thừa từ C, để tiếp tục thực hiện với giá trị lặp tiếp theo của vòng lặp.

Ngoài ra, các câu lệnh lặp cũng có thể sử dụng mệnh đề else. Nó sẽ được thực hiện khi vòng lặp kết thúc ( đến cuối của danh sách với for, hoặc khi gặp điều kiện sai với while ), nhưng không được thực hiện khi vòng lặp kết thúc bằng lệnh break. Xem xét ví dụ dưới đây để tìm số nguyên tố:

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

9. Lệnh pass

Câu lệnh pass không chứa gì thêm ngoài từ khóa. Nó có thể được sử dụng khi một lệnh được chờ đợi nhưng chương trình không cần có hành động nào. Ví dụ:

>>> while True:

… pass # Busy-wait for keyboard interrupt

10. Sự tương đương giữa true và một giá trị khác 0

Cũng như C/C++, bất kì một giá trị khác 0 nào cũng tương đương với true và ngược lại, một giá trị 0 tương đương với false. Như vậy:

if a != 0:

tương đương với

if a:

II.3. Hàm trong Python
1. Xây dựng hàm:

Cú pháp một hàm trong Python như sau:

def tên_hàm (tham_biến_1, tham_biến_2, …)

# lệnh …

return giá_trị_hàm

Trong đó def là từ khóa bắt buộc dùng để khai bó hàm, tiếp theo là tên hàm được đặt theo qui cách đặt tên, và cuối cùng là danh sách đối số(nếu có).

Ví dụ:

def binhPhuong(x):

return x*x

Câu lệnh đầu tiên ngay sau khai báo tên hàm có thể là một chuỗi kí tự tùy ý (string), được dùng để chỉ dẫn cho hàm (thường gọi là docstring).

Các tham số không cần xác định kiểu , Python sẽ tự xác định chúng dựa theo giá trị được truyền khi gọi hàm.

Python không phân biệt truyền tham biến hay truyền tham trị khi mà bản thân biến cũng không cần khai báo.

Ví dụ một hàm tính số Fibonacy

def fib(n):

print ‘n =’, n

if n > 1:

return n * fib(n − 1)

else:

print ‘end of the line’

return 1

hoặc như sau: ( in ra dãy Fibonacci đến một giới hạn tùy ý)

>>> def fib(n): # write Fibonacci series up to n

… “””Print a Fibonacci series up to n.”””

… a, b = 0, 1

… while 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

Do không có khai báo rõ ràng đầu hàm và kết thúc hàm ,chỉ có dấu : nên quy cách viết hàm phải khá phụ thuộc vào cách thụt vào của các lệnh.

Ở đây def fib(n): là khai báo hàm , nó phải được thụt vào it nhất , các lệnh tiếp theo nằm bên trong hàm do vậy phải thụt vào nhiều hơn, các lệnh print , if , else ngang hàng nhau, lệnh return n*fib(n-1) phải thụt vào nhiều hơn if…

Một định nghĩa hàm đưa tên hàm đó vào một bảng ký hiệu hiện thời. Giá trị của tên hàm là một kiểu mà được thông dịch như là một hàm người sử dụng định nghĩa. Giá trị đó có thể được đăng kí một tên khác mà nó cũng có thể sử dụng như một hàm. Điều này như là một thao tác đổi tên hàm:

>>> fib

>>> f = fib

>>> f(100)

1 1 2 3 5 8 13 21 34 55 89

Khi hàm không xác định kiểu giá trị trả về (giống như hàm fib ở trên) nó ngầm định trả về một giá trị gọi là None. Ta có thể xem giá trị này như sau:

>>> print fib(0)

None

Cũng rất đơn giản để viết một hàm trả về một danh sách chuỗi Fibonacci thay vì in ra nó:

>>> 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 >> f100 = fib2(100) # call it

>>> f100 # write the result

[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

2. Các kĩ thuật mở rộng với hàm:

2.1. Chồng hàm

Do không xác định cụ thể kiểu của các tham số khi khai báo hàm nên Python không có cách nào phân biệt các hàm chồng tên do vậy nó không hỗ trợ chế chồng hàm.

2.2. Hàm với tham số có giá trị mặc định

Python hỗ trợ hàm với tham số có giá trị mặc định , các tham số có thể truyền theo bất kỳ thứ tự nào nếu chỉ ra tên của tham số.

Xét 1 hàm sau

def info(object, spacing=10, collapse=1):

Khi ấy lời gọi hàm có thể là :

info(odbchelper)

–> object=odbchelper , spacing=10 , collapse=1

info(odbchelper, 12)

–> object=odbchelper , spacing=12 , collapse=1

info(odbchelper, collapse=0)

–> object=odbchelper , spacing=10 , collapse=0

info(spacing=15, object=odbchelper)

–> object=odbchelper , spacing=15, collapse =1;

Việc sử dụng tham số có giá trị mặc định trước giúp thuận tiện khi gọi hàm sẽ có ít tham số cần truyền hơn định nghĩa cho phép. Xét một ví dụ khác:

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 >> def function(a):

… pass

>>> function(0, a=0)

Traceback (most recent call last):

File “”, line 1, in ?

TypeError: function() got multiple values for keyword argument ‘a’

2.4. Hàm với danh sách đối số tùy ý:

Python cho phép khai báo 2 đối số đặc biệt cho phép tạo ra danh sách các đối số với số lượng tùy ý. Có nghĩa là mỗi khi gọi hàm đó. Ta có thể xác định bất kì số lượng đối số nào tùy ý. Ví dụ:

def function(first,second,*remaining):

statement1

statement2

Khi gọi hàm trên, phải cung cấp giá trị cho 2 đối số bắt buộc đầu tiên.Tuy nhiên với đối số thứ 3, bởi vì nó được đánh dấu với một dấu * nên bất kì đối số thật sự nào sau 2 đối số đầu tiên sẽ được cho vào một bộ và gán cho đối số còn lại.

>>> def print_tail(first,*tail):

… print tail

>>> print_tail(1, 5, 2, “omega”)

(5, 2, ‘omega’)

Nếu sử dụng ** trước một đối số thì nó sẽ gắn một từ điển chứa bất kì đối số từ khóa nòa trong các đối số truyền vào mà không phải là cho đối số bình thường. Ví dụ:

def make_dictionary(max_length = 10, **entries):

return dict([(key, entries[key]) for i, key in enumerate(entries.keys()) if i >> make_dictionary(max_length = 2, key1 = 5, key2 = 7, key3 = 9)

{‘key3’: 9, ‘key2’: 7}

Như vậy, các đối số đó sẽ được nằm trong một bộ. Trước các đối số có số lượng thay đổi, không có hoặc có vài đối số thông thường có thể xuất hiện. ví dụ:

def fprintf(file, format, *args):

file.write(format % args)

Tuy nhiên, chức năng này ít được sử dụng thường xuyên.

2.5. Dạng lambda (Hàm inline):

Bên cạnh việc đăng kí một giá trị trả về cho hàm với một biến, cũng có thể tạo ra các biến mà chứa các hàm. Python cung cấp từ khóa lambda để định nghĩa các hàm không được đặt tên có thể đăng kí với các biến. Ta phải đặt các đối số trước dấu hai chấm, và giá trị trả về đặt sau từ khóa lambda. Sau khi được đăng kí với một biến. có thể sử dụng biến này như là một hàm với các đối số và giá trị trả về như ví dụ sau:

>>> square = lambda x: x*x

>>> square(3)

9

Cũng có thể sử dụng các biến khác các thông số trong một lambda. Tuy nhiên chú ý rằng hàm lambda cũng sử dụng giá trị các biến trong phạm vi nó được tạo ra.

>>> prefix = “Note: ”

>>> def return_lambda(prefix):

… return lambda note: prefix + note

>>> prefix = “re: ”

>>> f = return_lambda(“Attn: “)

>>> f(“Carnivorous octopi”)

‘Attn: Carnivorous octopi’

Chú ý rằng tất cả các hàm trong Python có thể được lưu trữ thành các biến, và thực tế các biến là đơn giản nhất.

>>> make_note = return_lambda

>>> make_note(“See: “)(“lambda calculus”)

‘See: lambda calculus’

Đây cũng là một dạng hàm inline như trong một số ngôn ngữ khác

Ví dụ một hàm inline khác:

>>>f=lambda x:x*3

>>>f(2)

6

>>>f(‘Hello’)

‘HelloHelloHello’

Hàm inline chỉ được phép có 1 câu lệnh , lệnh đó chính là giá trị trả về của hàm.

Với từ khóa lambda, các hàm ẩn danh nhỏ có thể được tạo ra. Ví dụở đây là một hàm mà trả về tổng của 2 đối số của nó: “lambda a, b: a+b”. Các dạng lambda có thể được sử dụng ở bất cứ nơi nào đối tượng hàm được yêu cầu. Chúng bị hạn chế bởi một biểu thức đơn. Giống như các định nghĩa hàm lồng nhau, dạng lambda có thể tham chiếu các biến từ phạm vi chứa nó.

>>> def make_incrementor(n):

… return lambda x: x + n

>>> f = make_incrementor(42)

>>> f(0)

42

>>> f(1)

43

II.4. Lớp trong Python:

1. Cú pháp định nghĩa lớp:

Python sử dụng một cách thức khá đơn giản để định nghĩa một lớp.Cú pháp như sau:

class ClassName:

.

.

.

Cũng giống như định nghĩa hàm, một lớp phải được định nghĩa trước khi nó có thể sử dụng.Thực tế, các lệnh viết trong định nghĩa lớp thường sử dụng là các định nghĩa hàm.

Đối tượng lớp sẽ được tạo ra ngay sau khi định nghĩa lớp kết thúc.

2. Các đối tượng lớp:

Các đối tượng lớp trong Python hỗ trợ 2 thao tác : tham chiếu thuộc tính và thực thể.

2.1. Tham chiếu thuộc tính

Cú pháp tham chiếu thuộc tính của các đối tượng lớp cũng như cú pháp chuẩn cho tất cả các tham chiếu thuộc tính trong Python:

Obj.name

Giá trị của tên thuộc tính là tất cả các tên mà nằm trong không gian tên của lớp khi đối tượng được tạo ra.

Xét một lớp được định nghĩa như sau:

class MyClass:

“A simple example class”

i = 12345

def f(self):

return ‘hello world’

Thì MyClass.i và MyClass.f là các giá trị tham chiếu thuộc tính, trả về một số nguyên và một đối tượng hàm.

2.2. Thực thể lớp:

Thực thể lớp sử dụng ký hiệu hàm, mô tả đối tượng lớp như là một hàm không tham số và trả về một thực thể mới của lớp đó. Ví dụ (giả sử đã có lớp MyClass ở trên):

x = MyClass()

tạo ra một thực thể của lớp này và đăng kí đối tượng tạo ra với biến cục bộ x.

Việc thao tác một thực thể ( gọi một đối tượng lớp) tạo ra một đối tượng rỗng. Có nhiều lớp mục đích là để tạo ra các đối tượng với các thực thể thỏa mãn một trạng thái khởi tạo xác định. Vì thế một lớp có thể định nghĩa một phương thức đặc biệt tên là __init__( ), giống như sau:

def __init__(self):

self.data = []

Khi một lớp định nghĩa một phương thức __init__( ), thực thể lớp tự động gọi đến hàm __init__( ) cho thực thể vừa được tạo ra. Vì thế trong ví dụ trên, một thực thể khởi tạo mới có thể thu được bởi:

x = MyClass()

Tất nhiên, hàm __init__( ) có thể có đối số để linh hoạt hơn. Trong trường hợp đó, các đối số được truyền đến toán tử thực thể lớp thông qua hàm __init__( ).

Ví dụ:

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

3. Các đối tượng thực thể:

Đối tượng thực thể chỉ cho phép thao tác duy nhất là tham chiếu thuộc tính. Có 2 loại thuộc tính là: thuộc tính dữ liệu và phương thức.

Thuộc tính dữ liệu không cần phải khai báo, giống như biến cục bộ, chúng tự sinh ra ngay lần đầu gọi đến chúng. Ví dụ, nếu x là một thực thể của MyClass tạo ra ở trên, thì đoạn mã dưới đây sẽ in ra giá trị 16

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 thứ 2 là phương thức. Một phương thức là một hàm thuộc một đối tượng. Trong ví dụ trên MyClass.f là một hàm, còn x.f là một đối tượng phương thức, không phải một đối tượng hàm.

4. Các đối tượng phương thức:

Thông thường một đối tượng phương thức được gọi sau khi nó được chấp nhận:

x.f ( )

Trong ví dụ MyClass, lời gọi trên sẽ trả về xâu ‘hello world’. Tuy nhiên, không cần thiết phải gọi 1 phương thức theo đúng cách như trên, vì x.f là một đối tượng phương thức, có thể được lưu trữ lại và gọi ở lần tiếp theo, ví dụ:

xf = x.f

while True:

print xf( )

Đoạn mã này sẽ tiếp tục in ra dòng chữ ‘hello world’ cho đến khi ngừng chương trình.

5. Tính kế thừa:

5.1. Kế thừa đơn

Trong Python không có khái niệm Protected như C++ , chỉ có các hàm ,dữ liệu thành phần public hay private , và chúng được phân biệt qua tên , những tên bắt đầu bằng __ và kết thúc có tối đa 1 dấu _ là private

Ví dụ __x , __x_ , __abc là những biến private , __y__ ,a ,bc , xyz__ , x_ là những biến public . Tương tự như vậy với tên hàm.

Các biến và phương thức private chỉ có thể truy cập nội bộ trong class đó , các biến và phương thức public có thể truy xuất trong toàn bộ chương trình. Chỉ có 1 loại kế thừa là public.

Cú pháp khai báo một lớp con kế thừa như sau

class DerivedClassName(BaseClassName):

.

.

.

Xét ví dụ sau:

>>> class A:

sa=’Day la thuoc tinh cua lop A’

__pri=’Day la thuoc tinh rieng cua A’

def __init__(self):

print ‘Ham khoi tao cua lop A’

pass

>>> class B(A):

sb=’Day la thuoc tinh cua lop B’

def __init__(self):

print ‘Ham khoi tao cua lop B’

>>> b=B()

Ham khoi tao cua lop B

>>> b.sa

‘Day la thuoc tinh cua lop A’

>>> b.sb

‘Day la thuoc tinh cua lop B’

>>> b.__pri

Traceback (most recent call last):

File “”, line 1, in

b.__pri

AttributeError: B instance has no attribute ‘__pri’

>>>

Như thấy ở trên lớp A có 1 thuộc tính public là sa và 1 thuộc tính private là __pri mà lớp B kế thừa từ A cũng không truy xuất được. Một điểm lưu ý nữa là hàm khởi tạo của B không tự gọi hàm khởi tạo của A , do đó người lập trình phải gọi hàm khởi tạo của A .

5.2.Đa kế thừa

Khai báo Đa kế thừa cũng như đơn kế thừa ,chỉ việc thêm danh sách các lớp cơ sở vào trong cặp dấu () sau tên lớp:

class DerivedClassName(Base1, Base2, Base3):

.

.

.

Do Python không tự gọi hàm khởi tạo của các lớp cha nên thứ tự kế thừa không quan trọng.

Ví dụ đa kế thừa:

>>> class A:

sa=’Day la thuoc tinh lop A’

def __init__(self):

print ‘Ham khoi tao lop A’

pass

>>> class B:

sb=’Day la thuoc tinh lop B’

def __init__(self):

print ‘Ham khoi tao lop B’

pass

>>> class C(A,B):

sc=’Day la thuoc tinh lop C’

def __init__(self):

print ‘Ham khoi tao lop C’

pass

>>> c=C()

Ham khoi tao lop C

>>> c.sa

‘Day la thuoc tinh lop A’

>>> c.sb

‘Day la thuoc tinh lop B’

>>> c.sc

‘Day la thuoc tinh lop C’

>>>

6. Các kỹ thuật về chồng hàm, chồng toán tử, hàm và dữ liệu thành phần tĩnh:

6.1. Chồng hàm trong class

Python không hỗ trợ chồng hàm trong class khi mà không có một khai báo chặt chẽ về kiểu của dữ liệu các tham số truyền cho hàm , kiểu của chúng được xác định tuỳ theo giá trị truyền cho hàm lúc gọi hàm.

6.2 Chồng toán tử

Chồng toán tử trong Python được thực hiện bằng việc khai báo đè lên một số tên đặc biệt.Có rất nhiều toán tử có thể chồng trong Python.

Ví dụ phương thức __add__(self,x) sẽ định nghĩa lại phép cộng

__sub__(self,x) sẽ định nghĩa lại phép trừ

selfở đây là tham số bắt buộc phải có đối với mọi phương thức , nó giống con trỏthis trong C++

Xét lớp sau

>>> class A:

x=1

y=2.0

def __add__(self,a):

self.x-=a

self.y-=a

>>> a

>>> a=A()

>>> a.x

1

>>> a.y

2.0

>>> a+1

>>> a.x

0

>>> a.y

1.0

>>>

6.3 Hàm và dữ liệu thành phần tĩnh

a. Hàm (hay phương thức tĩnh ) được khai báo trong Python như sau

class C:

@staticmethod

def f(arg1, arg2, …): …

Hoặc

class C:

@classmethod

def f(arg1,arg2,…):….

Sự khác nhau giữa @staticmethod và @classmethod như sau:

– Nếu một hàm khai báo là @classmethod thì khi gọi hàm, hệ thống sẽ ngầm định truyền cho hàm tham số đầu tiên là thực thể của chính class đó , do đó hàm phải luôn sử dụng arg1 như là self (giống con trỏthis trong C++ ).

– Nếu một hàm khai báo là @staticmethod thì khi gọi hàm, hệ thống sẽ không ngầm định truyền cho hàm tham số đầu tiên là thực thể của chính class đó , do đó hàm này không thể biết được thực thể nào đã gọi mình.

Ví dụ:

>>> class C:

@staticmethod

def hello():

print ‘Hello’

>>> C.hello()

Hello

class D:

@classmethod

def hello():

print ‘Hello’

>>> D.hello()

Traceback (most recent call last):

File “”, line 1, in

D.hello()

TypeError: hello() takes no arguments (1 given)

>>>

Lỗi xảy ra trong lớp D là do hàm hello khi khai báo không nhận 1 tham số nào, nhưng khi được gọi, hệ thống tự thêm tham số đàu tiên là selfvào.

b. Dữ liệu thành phần tĩnh

Dữ liệu thành phần tĩnh của lớp được khai báo ngay sau tên lớp

>>> class A:

counter=0

def __init__(self):

self.__class__.counter+=1

print ‘Thuoc tinh tinh’,A.counter

print ‘Thuoc tinh cua lop’,self.counter

>>> A.counter

0

>>> a=A()

Thuoc tinh tinh 1

Thuoc tinh cua lop 1

>>> b=A()

Thuoc tinh tinh 2

Thuoc tinh cua lop 2

>>>

Thuộc tính tĩnh được chia sẻ bởi tất cả các thực thể của lớp và bản thân tên lớp đó
7. Kỹ thuật Odds and Ends đối với lớp
Trong Python thông đôi khi kỹ thuật này cũng được sử dụng để tạo ra các kiểu dữ liệu giống record trong Pascal hoặc struct trong C, đồng thời cùng với một vài thành phần dữ liệu được đặt tên. Ta dùng một định nghĩa lớp rỗng để thực hiện hiện điều 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

8. Các phương thức đặc biệt:

Có một số các phương thức được dành để sử dụng với các mục đích đặc biệt, nó được kết thúc với 2 dấu gạch dưới. Thông thường các phương thức đó được bắt đầu với một dấu gạch dưới để đánh dấu nó là ‘private’ với phạm vi mà nó được sử dụng trong đó.

Phương thức khởi tạo:

__init__

Một trong những mục đích của nó là để xây dựng một thực thể lớp, và tên đặc biệt cho phương thức này là ‘__init__’

Hàm __init__() được gọi trược khi một thực thể được trả về. Ví dụ:

class A:

def __init__(self):

print ‘A.__init__()’

a = A()

sẽ đưa ra

A.__init__()

__init__() có thể có đối số, trong trường hợp cần thông qua các đối số để tạo ra một thực thể. Ví dụ:

class Foo:

def __init__ (self, printme):

print printme

foo = Foo(‘Hi!’)

sẽ đưa ra:

Hi!

Sau đây là một ví dụ chỉ ra sự khác nhau giữa sử dụng và không sử dụng __init__():

class Foo:

def __init__ (self, x):

print x

foo = Foo(‘Hi!’)

class Foo2:

def setx(self, x):

print x

f = Foo2()

Foo2.setx(f,’Hi!’)

Sẽ in ra

Hi!

Hi!

Phương thức miêu tả:

__str__

Biến đổi một đối tượng thành một xâu, như là với câu lệnh print hoặc với hàm str(), nó có thể được đưa ra bởi __str__. Thông thường __str__ trả về một bản đã định dạng của nội dung đối tượng, điều này sẽ không được thường xuyên thực hiện. Ví dụ:

class Bar:

def __init__ (self, iamthis):

self.iamthis = iamthis

def __str__ (self):

return self.iamthis

bar = Bar(‘apple’)

print bar

sẽ in ra:

apple

__repr__

Hàm này cũng giống như __str__(). __repr__ được sử dụng để trả về biểu diển của một đối tượng trong dạng xâu. Thông thường nó có thể trả về đối tượng gốc. Ví dụ:

class Bar:

def __init__ (self, iamthis):

self.iamthis = iamthis

def __repr__(self):

return “Bar(‘%s’)” % self.iamthis

bar = Bar(‘apple’)

print bar

sẽ in ra:

Bar(‘apple’)

Các thuộc tính:

__setattr__

Đây là hàm quản lí các thuộc tính trong một lớp. Nó được cung cấp với tên và giá trị các biến được đăng kí. Tất nhiên, mỗi lớp có một __setattr__ mặc định đơn giản để thiết lập giá trị của các biến, nhưng cũng có thể gạt bỏ nó:

>>> class Unchangable:

… def __setattr__(self, name, value):

… print “Nice try”

>>> u = Unchangable()

>>> u.x = 9

Nice try

>>> u.x

Traceback (most recent call last):

File “”, line 1, in ?

AttributeError: Unchangable instance has no attribute ‘x’

__getattr___

Cũng giống với __setattr__, trừ hàm này được gọi khi ta truy nhập vào một thành viên lớp, và mặc định đơn giản trả về giá trị.

>>> class HiddenMembers:

… def __getattr__(self, name):

… return “You don’t get to see ” + name

>>> h = HiddenMembers()

>>> h.anything

“You don’t get to see anything”

__delattr__

Hàm này được gọi để xóa một đối tượng

>>> class Permanent:

… def __delattr__(self, name):

… print name, “cannot be deleted”

>>> p = Permanent()

>>> p.x = 9

>>> del p.x

x cannot be deleted

>>> p.x

9

9. Đóng gói lớp:

Bởi vì tất cả các thành phần của một lớp trong Python là có thể truy nhập bởi các hàm và phương thức bên ngoài lớp đó, không có cách nào để đóng gói các hàm ghi đè __getattr__, __setattr__ và __delattr__. Tuy nhiên, thực tế, để tạo ta một lớp hoặc một module để đơn giản người ta chỉ sử dụng phần giao diện đã dành cho và tránh truy cập đến vùng làm việc của module khác

II.5 Các kỹ thuật vềmodule
1. Khái niệm và cách sử dụng module trong python

Như đã nói,Python cho phép chia chương trình thành modules để có thể sử dụng lại trong các chương trình khác. Nó cũng có sẵn một tập hợp các modules chuẩn mà ta có thể sử dụng lại trong chương trình của ta. Các thư viện này cung cấp nhiều thứ, như file I/O, các lời gọi hệ thống, sockets,…Trong phần này chúng ta sẽ tìm hiểu các kỹ thuật, đặc điểm của các module.

Nếu thoát khỏi trình thông dịch Python và vào lại nó, những định nghĩa (các hàm và biến) đã viết sẽ bị mất. Vì thế, nếu muốn viết chương trình tồn tại được lâu, tốt nhất là sử dụng một trình soạn thảo để viết một file làm đầu vào cho trình biên dịch rồi chạy file đó. Cái này được gọi là một script (kịch bản). Hoặc khi muốn sử dụng một hàm đã xây dựng trong một vài chương trình mà không muốn copy định nghĩa của nó vào từng chương trình. Để hỗ trợ điều này, Python có một cách đặt các định nghĩa hàm trong một file và sử dụng chúng như một kịch bản hoặc trong một instance tương tác của trình thông dịch. Một file như vậy gọi là một module. Các định nghĩa từ một module có thể được nhập vào một module khác hoặc vào module chính (tập hợp các biến mà có thể truy nhập đến một script được thi hành tại mức cao nhất và trong chế độ tính toán).

Một module là một file chứa các định nghĩa và câu lệnh Python. Tên file là tên module với phần mở rộng là .py. Trong một module, tên của module (như là một xâu) là sẵn có như giá trị của biến toàn cục __name__. Ví dụ, dùng trình soạn thảo, soạn file fibo.py với nội dung như sau:

. # 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 >> import fibo

Thao tác này không nhập tên của các hàm đã được định nghĩa trong fibo trực tiếp vào trong bảng kí hiệu hiện thời; nó chỉ nhập tên của module fibo vào đó. Sử dụng tên module này để có thể truy nhập vào các hàm:

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

Để thuận tiện, một hàm trong module định sử dụng thường được đăng kí với 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

Một module có thể chứa các câu lệnh thực thi cũng như các định nghĩa hàm. Các câu lệnh đó được dùng để khởi tạo module đó. Chúng được thực hiện chỉ lần đầu tiên module đó được nhập.

Mỗi một module có bảng kí hiệu riêng của nó, cái mà được sử dụng như một bảng kí hiệu toàn cục cho tất cả các hàm được định nghĩa trong module đó. Vì thế, các biến toàn cục trong module có thể sử dụng mà không lo lắng về sự xung đột xảy ra với các biến toàn cục của người sử dụng module đó.

Module cũng có thể được nhập vào một module khác. Nó như là một thông lệ nhưng không yêu cầu phải đặt tất cả các câu lệnh import tại vị trí bắt đầu của một module (hoặc script). Tên module được nhập vào đó được đặt trong bảng kí hiệu toàn cục của module nhập module đó.

Để sử dụng modules trong Python, phải nhập nó bằng câu lệnh import. Ví dụ:

import math

Thao tác này sẽ nhập module chuẩn math. Tất cả các hàm trong module này được gọi bằng cách sử dụng qua tên module, ví dụ:

import math

print math.sqrt(10)

Có một biến thể của câu lệnh import mà nhập các tên từ một module trực tiếp vào bảng kí hiệu của module chứa module nhập đó. Ví dụ:

>>> from fibo import fib, fib2

>>> fib(500)

1 1 2 3 5 8 13 21 34 55 89 144 233 377

Cũng có một biến thể để nhập tất cả các tên mà một module định nghĩa:

>>> from fibo import *

>>> fib(500)

1 1 2 3 5 8 13 21 34 55 89 144 233 377

Thao tác này nhập tất cả các tên ngoại trừ những tên bắt đầu bằng dấu gạch dưới _

Đường dẫn tìm kiếm module
Khi một module tên là spam được nhập, trình thông dịch sẽ tìm một file tên là spam.py trong thư mục hiện hành, và sau đó trong danh sách các thư mục xác định bởi biến môi trường PYTHONPATH. Khi biến PYTHONPATH chưa được thiết lập hoặc khi file đó không được tìm thấy, việc tìm kiếm được tiếp tục trong một đường dẫn mặc định phụ thuộc khi cài đặt.

Thực tế, các module được tìm kiếm trong danh sách các thư mục được đưa ra bởi biến sys.path cái mà được khởi tạo từ thư mục chứa script vào ( hoặc thư mục hiện hành), PYTHONPATH và thư mục đường dẫn mặc định phụ thuộc vào cài đặt. Điều này cho phép chương trình Python biết cái mà chúng đang làm để sửa đổi hoặc thay thế đường dẫn tìm kiếm module.

2. Các module chuẩn

Python cung cấp một thư viện các module chuẩn. Một số module quan trọng được cài sẵn vào trình thông dịch. Có một module cụ thể đáng để chú ý là: sys, module này được cài sẵn vào mọi trình thông dịch Python. Các biến sys.ps1 và sys.ps2 định nghĩa các xâu được sử dụng như dấu nhắc sơ cấp và thứ cấp:

>>> import sys

>>> sys.ps1

‘>>> ‘

>>> sys.ps2

‘… ‘

>>> sys.ps1 = ‘C> ‘

C> print ‘Yuck!’

Yuck!

C>

Hai biến trên chỉ được định nghĩa nếu trình thông dịch ở chế độ tương tác.

Biến sys.path là một danh sách các xâu mà xác định đường dẫn tìm kiếm module của trình thông dịch. Nó được khởi tạo một đường dẫn mặc định từ biến môi trường PYTHONPATH, hoặc từ một giá trị mặc định được cài sẵn nếu PYTHONPATH không được thiết lập. Có thể sửa đổi nó sử dụng thao tác danh sách chuẩn:

>>> import sys

>>> sys.path.append(‘/ufs/guido/lib/python’)

Sau đây là danh sách đầy đủ các module chuẩn đã xây dựng trong Python. Một số module có kèm theo tên các nền tảng mà module đó được sử dụng:

__builtin__

__future__

__main__

_winreg(Windows)

aepack(Mac)

aetools(Mac)

aetypes(Mac)

aifc

AL(IRIX)

al(IRIX)

anydbm

applesingle(Mac)

array

asynchat

asyncore

atexit

audioop

autoGIL(Mac)

base64

BaseHTTPServer

Bastion

binascii

binhex

bisect

bsddb(Unix, Windows)

buildtools(Mac)

bz2

calendar

Carbon.AE(Mac)

Carbon.AH(Mac)

Carbon.App(Mac)

Carbon.CaronEvt(Mac)

Carbon.CF(Mac)

Carbon.CG(Mac)

Carbon.Cm(Mac)

Carbon.Ctl(Mac)

Carbon.Dlg(Mac)

Carbon.Evt(Mac)

Carbon.Fm(Mac)

Carbon.Folder(Mac)

Carbon.Help(Mac)

Carbon.List(Mac)

Carbon.Menu(Mac)

Carbon.Mlte(Mac)

Carbon.Qd(Mac)

Carbon.Qdoffs(Mac)

Carbon.Qt(Mac)

Carbon.Res(Mac)

Carbon.Scrap(Mac)

Carbon.Snd(Mac)

Carbon.TE(Mac)

Carbon.Win(Mac)

cd(IRIX)

cfmfile(Mac)

cgi

CGIHTTPServer

cgitb

chunk

cmath

cmd

code

codecs

codeop

collections

ColorPicker(Mac)

colorsys

commands(Unix)

compileall

compiler

compiler.ast

compiler.visitor

ConfigParser

contextlib

Cookie

cookielib

copy

copy_reg

cPickle

cProfile

crypt(Unix)

cStringIO

csv

ctypes

curses

curses.ascii

curses.panel

curses.textpad

curses.wrapper

datetime

dbhash(Unix, Windows)

dbm(Unix)

decimal

DEVICE(IRIX)

difflib

dircache

dis

distutils

distutils.archive_util

distutils.bcppcompiler

distutils.ccompiler

distutils.cmd

distutils.command

distutils.command.bdist

distutils.command.bdist_dumb

distutils.command.bdist_packager

distutils.command.bdist_rpm

distutils.command.bdist_wininst

distutils.command.build

distutils.command.build_clib

distutils.command.build_ext

distutils.command.build_py

distutils.command.build_scripts

distutils.command.clean

distutils.command.config

distutils.command.install

distutils.command.install_data

distutils.command.install_headers

distutils.command.install_lib

distutils.command.install_scripts

distutils.command.register

distutils.command.sdist

distutils.core

distutils.cygwinccompiler

distutils.debug

distutils.dep_util

distutils.dir_util

distutils.dist

distutils.emxccompiler

distutils.errors

distutils.extension

distutils.fancy_getopt

distutils.file_util

distutils.filelist

distutils.log

distutils.msvccompiler

distutils.mwerkscompiler

distutils.spawn

distutils.sysconfig

distutils.text_file

distutils.unixccompiler

distutils.util

distutils.version

dl(Unix)

doctest

DocXMLRPCServer

dumbdbm

dummy_thread

dummy_threading

EasyDialogs(Mac)

elementtree

email

email.charset

email.encoders

email.errors

email.generator

email.header

email.iterators

email.message

email.mime

email.mime.audio

email.mime.base

email.mime.image

email.mime.message

email.mime.multipart

email.mime.nonmultipart

email.mime.text

email.parser

email.utils

encodings.idna

errno

exceptions

fcntl(Unix)

filecmp

fileinput

findertools(Mac)

FL(IRIX)

fl(IRIX)

flp(IRIX)

fm(IRIX)

fnmatch

formatter

fpectl(Unix)

fpformat

FrameWork(Mac)

ftplib

functools

gc

gdbm(Unix)

gensuitemodule(Mac)

getopt

getpass

gettext

GL(IRIX)

gl(IRIX)

glob

gopherlib

grp(Unix)

gzip

hashlib

heapq

hmac

hotshot

hotshot.stats

htmlentitydefs

htmllib

HTMLParser

httplib

ic(Mac)

icopen(Mac)

imageop

imaplib

imgfile(IRIX)

imghdr

imp

inspect

itertools

jpeg(IRIX)

keyword

linecache

locale

logging

macerrors(Mac)

macfs(Mac)

MacOS(Mac)

macostools(Mac)

macpath

macresource(Mac)

mailbox

mailcap

marshal

math

md5

mhlib

mimetools

mimetypes

MimeWriter

mimify

MiniAEFrame(Mac)

mmap

modulefinder

msilib(Windows)

msvcrt(Windows)

multifile

mutex

Nav(Mac)

netrc

new

nis(UNIX)

nntplib

operator

optparse

os

os.path

ossaudiodev(Linux, FreeBSD)

parser

pdb

pickle

pickletools

pipes(Unix)

PixMapWrapper(Mac)

pkgutil

platform

popen2(Unix, Windows)

poplib

posix(Unix)

posixfile(Unix)

pprint

profile

pstats

pty(IRIX, Linux)

pwd(Unix)

py_compile

pyclbr

pydoc

Queue

quopri

random

re

readline(Unix)

repr

resource(Unix)

rexec

rfc822

rgbimg

rlcompleter

robotparser

runpy

sched

ScrolledText(Tk)

select

sets

sgmllib

sha

shelve

shlex

shutil

signal

SimpleHTTPServer

SimpleXMLRPCServer

site

smtpd

smtplib

sndhdr

socket

SocketServer

spwd(Unix)

sqlite3

stat

statvfs

string

StringIO

stringprep

struct

subprocess

sunau

SUNAUDIODEV(SunOS)

sunaudiodev(SunOS)

symbol

sys

syslog(Unix)

tabnanny

tarfile

telnetlib

tempfile

termios(Unix)

test

test.test_support

textwrap

thread

threading

time

timeit

Tix

Tkinter

token

tokenize

trace

traceback

tty(Unix)

turtle(Tk)

types

unicodedata

unittest

urllib

urllib2

urlparse

user

UserDict

UserList

UserString

uu

uuid

videoreader(Mac)

W(Mac)

warnings

wave

weakref

webbrowser

whichdb

winsound(Windows)

wsgiref

wsgiref.handlers

wsgiref.headers

wsgiref.simple_server

wsgiref.util

wsgiref.validate

xdrlib

xml.dom

xml.dom.minidom

xml.dom.pulldom

xml.parsers.expat

xml.sax

xml.sax.handler

xml.sax.saxutils

xml.sax.xmlreader

xmlrpclib

zipfile

zipimport

zlib

3. Thư viện các module chuẩn:

Phần này sẽ trình bày về một số module chuẩn đã được xây dựng sẵn trong Python.

3.1. Giao diện hệ điều hành

Module os cung cấp rất nhiều hàm tương tác với hệ điều hành:

>>> import os

>>> os.system(‘time 0:02’)

0

>>> os.getcwd()

# Return the current working directory

‘C:\\Python24’

>>> os.chdir(‘/server/accesslogs’)

Hai hàm dir( ) và help( ) được dùng như những trợ giúp khi làm việc vói các modules lớn như os:

>>> import os

>>> dir(os)

>>> help(os)

Đối với nhiệm vụ quản lý thư mục và file hằng ngày, module shutil cung cấp sự tương tác ở mức độ cao hơn, sử dụng dễ dàng hơn:

>>> import shutil

>>> shutil.copyfile(‘data.db’, ‘archive.db’)

>>> shutil.move(‘/build/executables’, ‘installdir’)

3.2 Tệp với các kí tự đại diện

Module glob cung cấp một hàm để tạo danh sách từ việc tìm kiếm một thư mục dùng các kí tự đại diện. Ví dụ:

>>> import glob

>>> glob.glob(‘*.py’)

[‘primes.py’, ‘random.py’, ‘quote.py’]

3.3 Đối số dòng lệnh

Các script tiện ích phổ biến thường cần thiết lúc xử lý đối số dòng lệnh. Các đối số này được lưu trữ trong thuộc tính argv của module sys như một danh sách.Ví dụ sau đưa ra kết quả khi chạy “python demo.py one two three” tại dòng lệnh:

>>> import sys

>>> print sys.argv

[‘demo.py’, ‘one’, ‘two’, ‘three’]

3.4. Sự đổi hướng xuất lỗi và phần kết thúc chương trình

Module sys cũng có các thuộc tính cho stdin, stdout và stderr . Đoạn mã sau để tạo ra các cảnh báo và thông điệp lỗi làm cho chũng xuất hiện ngay cả khi stdout được định hướng lại

>>> sys.stderr.write(‘Warning, log file not found starting a new one\n’)

Warning, log file not found starting a new one

Hầu hết cách định hướng để kết thúc một script là xử dụng “sys.exit()”.

3.5. Kết hợp các kiểu xâu

module re cung cấp các công cụ biểu thức thông dụng cho việc xử lý xâu nâng cao .Đối với các thao tác và biểu diễn phức tạp ,các biểu thức chính qui đưa ra các giải pháp ngắn gọn và tối ưu. Ví dụ:

>>> import re

>>> re.findall(r’\bf[a-z]*’, ‘which foot or hand fell fastest’)

[‘foot’, ‘fell’, ‘fastest’]

>>> re.sub(r'(\b[a-z]+) \1′, r’\1′, ‘cat in the the hat’)

‘cat in the hat’

3.6. Thư viện các hàm toán học

Danh sách các module số và toán học bao gồm:

math

Các hàm toán học (sin() v.v…).

cmath

Các hàm toán học cho số phức.

decimal

Khai báo của các dạng số học thập phân tổng quát

random

Sinh ra các số “giả” ngẫu nhiên với các hàm phân bố xác suất thông thường.

itertools

Các hàm sinh ra các “iterators” sử dụng trong các vòng lặp hiệu quả

functools

Các hàm và thao tác có thứ tựưu tiên cao hơn trên các đối tượng gọi được

operator

Tất cả các toán tử chuẩn của Python được cài đặt sẵn

Module math cung cấp các truy cập tới các hàm thư viện cơ bản của C đối với các phép toán trên số thực

>>> import math

>>> math.cos(math.pi / 4.0)

0.70710678118654757

>>> math.log(1024, 2)

10.0

Module random cung cấp một cách thức để tạo ra sự lựa chọn ngẫu nhiên

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

Sau đây, ta sẽ tìm hiểu về các hàm được xây dựng trong 2 module math và cmath.

a. Các hàm toán học trong module math:

Modul này luôn sẵn dùng. Nó cung cấp phương thức truy nhập các hàm toán học được định nghĩa theo chuẩn C.

Module math cung cấp các hàm dưới đây. Tất cả đều trả về số thực ngoại trừ một số trường hợp đặc biệt.

ceil(

x)

Hàm trả về giá trị cận trên của số thực x, tương ứng với giá trị nguyên nhỏ nhất lớn hơn x.

fabs(

x)

Giá trị tuyệt đối của x.

floor(

x)

Hàm trả về giá trị cận dưới của số thực x, tương ứng với giá trị nguyên lớn nhất nhỏ hơn x.

.

fmod(

x, y)

Trả về fmod(x,y), được định nghĩa theo chuẩn thư viện C. Chú ý rằng trong Python phép toán x % y có thể không trả về cùng một kết quả tương tự. Thực tế trong chuẩn thư viện C thì fmod(x,y) trả về chính xác(phép toán, độ chính xác vô hạn) bằng x-n*y với 1 vài số nguyên n có cùng kết quả với dấu của x và độ lớn trị tuyệt đối của y. Trong khi đó, đối với Python thì phép toán x % y trả về kết quả là bao gồm cả dấu của y, và nó ko thểước tính chính xác cho các đối số thực.Ví dụ, fmod(-1e-100,1e100) là -1e-100, nhưng kết quả của -1e-100 % 1e100 là -1e-100,điều này không thể đưa ra kết quả chính xác đối với số thực, và làm tròn 1e100. Chính vì nguyên nhân này, hàm fmod() thường được ưu tiên khi làm việc với số thực, với x % y trong Python thì được ưu tiên với số nguyên.

frexp(

x)

Trả về phần định trị và số mũ của x dưới dạng (m,e). m có giá trị thực còn e là số nguyên với x == m*2**e. Nếu x = 0, kết quả là (0.0,0), còn 0.5 <= abs(m) =2**52 thì tất nhiên sẽ không có các bít phân số.

Các hàm mũ và logarit:

exp(

x)

Trả về e**x

log(

x[, base])

Trả về logarit của x với cơ số đưa ra là base. Nếu không đưa cơ cố base, thì tự động trả về logarit tự nhiên của x( logarit với cơ số e).

log10(

x)

Trả về logarit cơ số 10 của x.

pow(

x, y)

Trả về x ** y

sqrt(

x)

Trả về căn bậc 2 của x.

Các hàm lượng giác:

acos(

x)

Trả về arc coosin của x theo radian.

asin(

x)

Trả về arc sin của x theo radian

atan(

x)

Trả về arc tang của x theo radian

atan2(

y, x)

Trả về atan(y/x) theo radian. Kết quả nằm trong khoảng từ -pi đến pi. Vector trong mặt phẳng từ điểm gốc tọa độ tới điểm có tọa độ (x,y) tạo một góc với trục tọa độ X . Điểm của atan2() mà dấu của cả hai đầu vào được biết đến nó, vì vậy nó có thể tính toán chính xác độ của góc. Ví dụ, atan(1) và atan2(1,1) đều bằng pi/4 nhưng atan2(-1,-1) lại bằng –pi/4.

cos(

x)

Trả về giá trị cosin của x

hypot(

x, y)

Trả về dạng Oclit của sqrt(x*x+y*y).Đây là độ dài véc tơ từ gốc tọa độ tới điểm có tọa độ (x,y).

sin(

x)

Trả về sin của x theo radian

tan(

x)

Trả về tang của x theo radian.

Hàm chuyển đổi góc:

degrees(

x)

Chuyển góc x từ radian sang độ.

radians(

x)

Chuyển góc x từ độ sang radian.

Các hàm hypebon:

cosh(

x)

Trả vè hyperbolic cosin của x.

sinh(

x)

Trả về hyperbolic sin của x.

tanh(

x)

Trả về hyperbolic tang của x.

Các hằng số toán học được định nghĩa sẵn:

pi

Sốpi = 3.14159265358979….

e

Sốe.

b. Các hàm toán học cho số phức trong module cmath:

Module này cung cấp cách truy nhập vào các hàm toán học cho số phức. Các hàm này gồm có:

acos(

x)

Trả về arccos của x. Có 2 miền được chọn: 1 miền kéo dài về phía phải từ 1 liên tục tới ∞. Miền còn lại kéo dài về phía trái từ -1 liên tục tới -∞.

acosh(

x)

Trả về hypedolic arccos của x. Chỉ có một miền được lấy ra, kéo dài về phía trái từ 1 liên tục cho tới -∞.

asin(

x)

Trả về arcsin của x.Có dải giá trị cũng giống như arccos().

asinh(

x)

Trả về hyperbolic arcsin của x. Có 2 miền giá trị được lấy ra, kéo dài liên tục về bên trái từ ±1j tới ±-∞j. Những miền này cần tính toán đến các lỗi để chính xác hơn. Miền chính xác được lấy ra sẽ mở rộng theo trục ảo, một liên tục từ 1j tới ∞j từ phía phải và một liên tục từ -1j tới -∞j từ phía trái.

atan(

x)

Trả về arc tang của x. Có 2 miền được lấy ra: Một kéo dài liên tục từ 1j theo trục sốảo tới ∞j từ phía trái. Miền khác kéo dài liên tục từ -1j dọc theo trục sốảo tới ∞j từ phía trái.( Điều này sẽ chắc chắn thay đổi vì với miền cao hơn sẽ liên tục từ nhiều phía khác).

atanh(

x)

Trả về hyperbolic arc tang của x. Có 2 miền giá trị được lấy ra: Một kéo dài liên tục từ 1 dọc theo trục số thực tới ∞. Miền còn lại kéo dài liên tục từ -1 dọc theo trục số thực tới -∞.( Điều này chắc chắn sẽ bị thay đổi vì miền phải lấy ra trở nên liên tục từ phía khác)

cos(

x)

Trả về cosin của x.

cosh(

x)

Trả về hyperbolic cosin của x.

exp(

x)

Trả về giá trị mũ e**x.

log(

x[, base])

Trả về logarit của x với cơ số là base. Nếu base ko được đưa ra, trả về giá trị logarit tự nhiên của x. Có một miền được lấy ra, từ 0 dọc theo miền âm trục số thực tới -∞. Được thay đổi trong phiên bản 2.4 : đối số base được thêm vào.

log10(

x)

Trả về logarit cơ số 10 của x. Có miền tương tự như hàm log()

sin(

x)

Trả về sin của x.

sinh(

x)

Trả về hyperbolic sin của x.

sqrt(

x)

Trả về căn bậc 2 của x. Miền được lấy ra tương tự như hàm log().

tan(

x)

Trả về tang của x.

tanh(

x)

Trả về hyperbolic tang của x.

Các hằng số đươc định nghĩa trong module:

pi

Hằng số pi, tương tự như số thực

e

Hằng số e, tương tự như số thực

Chú ý rằng việc lựa chọn các hàm trong module cmath cũng gần tương tự như trong module math nhưng không hoàn toàn giống. Lý do khiến người ta xây dựng lên cả 2 module phân biệt này là vì có người sử dụng không thích dùng trong số phức, và có lẽ không cần quan tâm chúng là gì. Để xử lý với số phức họ có thể dùng hàm math.sqrt(-1), và giá trị trả về của các hàm trong cmath thì luôn là số phức, mặc dù giá trị đó có thể rõ ràng là số thực ( trong trường hợp số phức có phần ảo là 0).

3.7. Truy cập internet

Có một sốmodule để truy cập internet và xử lý các giao thức internet. Hai module đơn giản nhất là urllib2 cho việc nhận dữ liệu từ url và smtplib cho gửi mail:

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

Nov. 25, 09:43:32 PM EST

>>> import smtplib

>>> server = smtplib.SMTP(‘localhost’)

>>> server.sendmail(‘[email protected]’, ‘[email protected]’,

“””To: [email protected]

From: [email protected]

Beware the Ides of March.

“””)

>>> server.quit()

3.8 Xử lý ngày và thời gian với module datetime

Module datetime cung cấp các lớp để thao với ngày và thời gian cho cả yêu cầu đơn giản và phức tạp. Module này cũng hỗ trợ các đối tượng nhận định yếu tố thời gian.

# 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

3.9. Nén dữ liệu

Các định dạng nén và lưu trữ dữ liệu phổ biến được hỗ trợ trực tiếp bởi rất nhiều thủ tục, bao gồm:zlib,gzip,bz2,zipfile và tarfile. Ví dụ:

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

3.10. Đánh giá khả năng thực hiện

Một số ngưòi sử dụng Python quan tâm sâu sắc trong việc tìm hiểu sự thực thi tương đối của các cách tiếp cận khác nhau tới cùng một vấn đề

Chẳng hạn có thể thử chức năng packing và unpacking một tuple thay vì phương pháp truyền thống là đối chỗ đối sô. Module timeit cung cấp một ưu điểm thực hiện với mức độ vừa phải

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

3.11. Kiểm tra chất lượng

Một phương pháp để phát triển phần mềm chất lượng cao là viết chương trình kiểm tra cho mỗi hàm lúc nó được phát triển và chạy kiểm tra thường xuyên trong suốt quá trình phát triển

Module doctest cung cấp một công cụ cho việc kiểm tra một module và kiểm tra hợp lệ được nhúng trong một docstring của chương trình.Việc tạo kiểm tra cũng đơn giản như cắt và dán một lời gọi thông thường cùng với kết quả của nó vào docstring đó.

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

Module unittest không cung cấp hiệu qua như module doctest nhưng nó cho phép một tập hỗn hợp của các kiểm tra được duy trì trong một file 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

3.12 Định dạng đầu ra

Module repr cung cấp một phiên bản mới của hàm rept( ) tuỳ biến đối với việc hiển thị ngắn gọn của các tập lớn hoặc được lồng nhau ở mức sâu.

>>> import repr

>>>repr.repr(set(‘supercalifragilisticexpialidocious’))

“set([‘a’, ‘c’, ‘d’, ‘e’, ‘f’, ‘g’, …])”

Module pprint đưa ra điều khiển phức tạp hơn khi in các đối tượng đã xây dựng sẵn và do người dùng định nghĩa theo một phương thức mà trình biên dịch có thể hiểu được.

Khi kết quả dài hơn một dòng, ”pretty printer “ xuống dòng và thụt vào đầu dòng để thể hiện cấu trúc dữ liệu rõ ràng hơn

Ví dụ 2:

>>> import pprint

>>> t = [[[[‘black’, ‘cyan’], ‘white’, [‘green’, ‘red’]], [[‘magenta’,

… ‘yellow’], ‘blue’]]]

>>> pprint.pprint(t, width=30)

[[[[‘black’, ‘cyan’],

‘white’,

[‘green’, ‘red’]],

[[‘magenta’, ‘yellow’],

‘blue’]]]

Module textwrap định dạng đoạn văn bản để lấp đầy chiều rộng màn hình đươc cho trước:

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

Module locale truy cập một cơ sở dữ liệu của các định dạng dữ liệu xác định . Nhóm các thuộc tính của các hàm trong module locale cung cấp một phương thức trực tiếp định dạng các số với việc tách thành các 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’

3.13. Kĩ thuật templating (tạm thời)

Module string cung cấp một lớp Template linh hoạt với cấu trúc được đơn giản hoá phù hợp cho việc soạn thảo. Điều này cho phép người sử dụng tuỳ biến các ứng dụng của họ mà không cần phải thay đổi ứng dụng.

Định dạng này sử dụng các placeholder( biến giữ chỗ) đuợc tạo thành bởi ký hiệu $ sử dụng các định danh hợp lệ của Python (chỉ gồm các ký tự chữ, số và ký tự gạch dưới). Bao quanh placeholder với dấu ngoặc {}cho phép nó đi kèm với các ký tự chữ số mà không có dấu cách xen vào giữa. Ví dụ:

>>> 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.’

Phương thức substitute tạo ra một lỗi KeyError khi một placeholder không được cung cấp trong một từ điển hay một đối số từ khoá. Trong một ứng dụng dạng mail-mail, người sử dụng cung cấp dữ liệu có thể không đầy đủ và phương thức safe_substitute có thể thích hợp hơn—Nó sẽ để nguyên placeholder nếu dữ liệu bi lỗi

>>> 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 Template có thể xác định một phân định tuỳ chọn. Chẳng hạn ,một tiện ích đổi tên cho một trình duyệt ảnh có thể chọn để dùng kí hiệu % làm placeholder như ngày hiện tại, số chuỗi ảnh hay kiểu định dạng file ả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

3.14. Làm việc với các lớp bản ghi dữ liệu nhị phân

Module struct cung cấp các hàm pack() và unpack() để làm việc với các định dạng bản ghi nhị phân chiều dài thay đổi. Chương trình sau chỉ ra làm thế nào lặp các thông tin header trong một file Zip ( với các mã đóng gói “H” và “L” tương ứng số không dấu 2 và 4 bytes)

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

3.15. Kỹ thuật đa tuyến (Multi-threading)

Đa tuyến (Threading) là một kĩ thuật cho các nhiệm vụ tách riêng mà không phụ thuộc lấn nhau. Các tuyến có thể được sử dụng để nâng cao tính đáp ứng của các ứng dụng mà chấp nhận người sử dụng nhập số liệu trong khi các nhiệm vụ khác vẫn đang chạy.

Đoạn mã sau chỉ ra cách mà module threading có thể thực hiện các nhiệm vụ trong khi chương trình chính vẫn tiêp tục chạy

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.’

Vấn đề khó khăn chủ yếu của các ứng dụng đa tuyến là các tuyến này cùng chia sẻ dữ liệu và các tài nguyên khác.

Module threading cũng cung cấp một sô công cụ đồng bộ hoá bao gồm locks, events, conditional variables và semaphore.

Mặc dù các công cụ này là rất mạnh, nhưng có những khó khăn trong khi thiết kế để tránh các lỗi. Một phương pháp hữu hiệu là tập trung tất cả sự truy cập tới một tài nguyên trong một thread đơn, sau đó sử dụng thủ tục Queue để sử dụng thread này với các yêu cầu từ các thread khác. Ứng dụng sử dụng đối tượng Queue cho việc liên lạc các thread bên trong chương trình và sự kết hợp là dễ dàng hơn để thiết kế, dễ đọc hơn và đáng tin cậy hơn.

3.16. Thao tác Logging

Module logging cung cấp thao tác thoát khỏi hệ thống với đủ chức năng và linh hoạt.

Đơn giản, một thông điệp log được gửi tới file hoặc 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 code này đưa ra dòng thông báo sau:

WARNING:root:Warning:config file server.conf not found

ERROR:root:Error occurred

CRITICAL:root:Critical error — shutting down

Theo mặc định, thông điệp thông tin và sữa lỗi có thể bị cấm và đầu ra chỉ được gửi tới các lỗi chuẩn. Các lựa chọn đầu ra bao gồm các thông điệp định tuyến thông qua email, datagram, socket hay HTTP server. Một bộ lọc có thể chọn định tuyến khác nhau dựa trên quyền ưu tiên của thông điệp: DEBUG, WARNING, ERROR VÀ CRITICAL

Thao tác thoát khỏi hệ thống có thể được cấu hinh trực tiếp từ Python hoặc được nạp từ file cấu hình có thể chỉnh sửa đối vói logging tuỳ ý mà không cần thay đổi ứng dụng

3.17. Các tham chiếu lỏng lẻo:

Pyhton tự động quản lý bộ nhớ (đếm số lần tham chiếu của hầu hết các đối tượng và tập hợp không hợp lệ để loại trừ chúng theo chu kì). Bộ nhớ sẽ được giải phóng ngay sau khi tham chiếu cuối cùng tới nó được loại bỏ.

Phương pháp này làm việc tốt đối với hầu hết ứng dụng nhưng đôi khi, các đối tượng cần được theo dõi trong suốt quá trình chúng được sử dụng, nhưng việc theo dõi đó lại tạo ra một tham chiếu lâu dài. Module

weakref cung cấp các công cụ cho theo dõi đối tượng mà không cần tạo một tham chiếu. Khi đối tượng không còn cần nữa thì nó sẽ tự động bị xoá đi từ một bảng. Xét một ví dụ:

>>> 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 “”, line 1, in -toplevel-

d[‘primary’]

# entry was automatically removed

File “C:/PY24/lib/weakref.py”, line 46, in __getitem__

o = self.data[key]()

KeyError: ‘primary’

3.18. Các công cụ làm việc vói danh sách

Module array cung cấp đối tượng array() giống như một danh sách lưu trữ chỉ dữ liệu cùng loại và lưu trữ nó liên tiếp nhau. Ví dụ sau đây chỉ ra một mảng các số được lưu trữ như số nhị phân không dấu 2 byte (mã kiểu “H”) hơn là 16 bytes thông dụng cho một mục đối với danh sách thông thường của đối tượng int của Python.

>>> from array import array

>>> a = array(‘H’, [4000, 10, 700, 22222])

>>> sum(a)

26932

>>> a[1:3]

array(‘H’, [10, 700])

Module collections cung cấp đối tượng deque() cũng giống như danh sách nhưng tốc độ thêm vào và lấy ra từ phía trái nhanh hơn nhưng tìm kiếm bên trong chậm hơn. Đối tượng này phù hợp tốt cho sự thục hiện queue 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 ra, để lựa chọn các thao tác trên danh sách, thư viện cũng đưa ra các công cụ khác như module bisect với các hàm cho các thao tác trên danh sách được lưu trữ

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

Module heap cung cấp các hàm cho việc thao tác các heap dựa trên danh sách thông thường. Phần tử có giá trị thập nhất luôn ở vi trí 0 . Đây là một ứng dụng hữu ích khi phải truy cập thường xuyên tới phần tử nhỏ nhất nhưng không muốn sắp xếp 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]

3.19. Số học trên dấu phẩy động hệ mười

Module decimal đưa ra kiểu dữ liệu Decimal các phép toán số học với dấu phẩy động. So với các thao tác trên kiểu float đã có sẵn của dấu phẩy động nhị phân, lớp mới này đặc biệt có ích đối với các ứng dụng tài chính và những người sử dụng khác cần việc biểu diển chính xác số thực, kiểm soát độ chính xác, điều chỉnh việc làm tròn đúng qui tắc hay các yêu cầu điêu chỉnh, hay các ứng dụng mà người sử dụng chấp nhận kết quả được tính toán bằng tay.

Chẳng hạn tính 5% thuế trên 70 cent tiền điện thoại đưa lại kết quả khác nhau trong kiểu số thực và số phẩy động nhị phân. Sự khác nhau này trở nên có ý nghĩa nếu kết quả được làm tròn tới cent gấn nhất

>>> from decimal import *

>>> Decimal(‘0.70’) * Decimal(‘1.05’)

Decimal(“0.7350”)

>>> .70 * 1.05

0.73499999999999999

Việc biểu diễn chính xác cho phép lớp Decimal thực hiện công việc tính toán và kiểm tra đẳng thức điều mà không phù hợp đối với số dấu phẩy động nhị phân

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

Module decimal cung cấp số và độ chính xác theo yêu cầu

>>> getcontext().prec = 36

>>> Decimal(1) / Decimal(7)

Decimal(“0.142857142857142857142857142857142857”)

4. Hàm dir( )

Hàm cài sẵn dir( ) được sử dụng để tìm ra các tên mà một module định nghĩa. Nó trả về một danh sách đã sắp xếp các xâu. Ví dụ:

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

Nếu không có các đối số, dir( ) liệt kê các tên đã định nghĩa hiện thời:

>>> a = [1, 2, 3, 4, 5]

>>> import fibo

>>> fib = fibo.fib

>>> dir()

[‘__builtins__’, ‘__doc__’, ‘__file__’, ‘__name__’, ‘a’, ‘fib’, ‘fibo’, ‘sys’]

Chú ý rằng nó liệt kê tất cả các loại tên: biến, module, hàm v.v…

dir( ) không liệt kê các tên của các hàm và biến được cài sẵn. Nếu muốn một danh sách của chúng, chúng phải được định nghĩa trong một module chuẩn __builtin__:

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

echo.echofilter(input, output, delay=0.7, atten=4)

II.6. Thao tác vào và ra:

1.Input

Python có 2 hàm được thiết kế để nhận dữ liệu trực tiếp từ người sử dụng:

• input()

• raw_input()

Đó cũng là cách đơn giản để đọc một file, và đọc từ stdin nếu cần thiết

raw_input()

raw_input() yêu cầu người sử dụng nhập vào một chuỗi dữ liệu (kết thúc bằng một dòng mới), và đơn giản trả về một chuỗi. Nó cũng có thể đưa ra một đối số để hiện thị như một lời nhắc trước khi người sử dụng vào dữ liệu. Ví dụ:

print raw_input(‘What is your name?’)

sẽ in ra:

What is your name?

input()

input() sử dụng như raw_input để đọc một chuỗi dữ liệu và sau đó thực hiện nó nếu đó là một chương trình Python, và trả về một giá trị kết quả mà chương trình đó trả về and then returns the value that results. Ví dụ vào:

[1,2,3]

Sẽ trả về một danh sách chứa các số đó, nếu nó được đăng kí trực tiếp trong script đó.

Cũng có thể dùng nhiều biểu thức phức tạp, ví dụ, trong một script có:

x = input(‘What are the first 10 perfect squares? ‘)

Người sử dụng có thể nhập:

map(lambda x: x*x, range(10))

biểu thức nhập vào đó sẽ được thực hiện và cho ra một câu trả lời chính xác dạng danh sách. Chú ý rằng câu lệnh nhập vào đó chỉ được viết trên một dòng.

input() thường được sử dụng để nhập các chương trình nhỏ. Còn raw_input() thường dùng trả về các chuỗi nhận được vào một kiểu dữ liệu chưa xác định, giống như:

x = None

while not x:

try:

x = int(raw_input())

except ValueError:

print ‘Invalid Number’

nếu dùng input() cần sử dụng thêm hàm eval() để xác định kiểu nhập vào.

File Input

Các đối tượng file

Python có các kiểu file được cài sẵn. Các file có thể mở bằng cách sử dụng hàm xây dựng kiểu file:

f = file(‘test.txt’, ‘r’)

Điều này có nghĩa là file f được mở để đọc. Đối số đầu tiên là tên file và đối số thứ 2 là chế độ mở file, bao gồm, ‘r’, ‘w’ hoặc ‘rw’

Cách phổ biến nhất để đọc một file là lặp lại tuần tự cho đến hết file:

f = open(‘test.txt’, ‘r’)

for line in f:

print line[0]

f.close()

Đoạn mã trên sẽ in ra kí tự đầu tiên của mỗi dòng trong file.

Cũng có thể đọc với số lượng giới hạn các kí tự tại một thời điểm, giống như sau:

c = f.read(1)

while len(c) > 0:

if len(c.strip()) > 0: print c,

c = f.read(1)

Đoạn mã này sẽ lặp lại việc đọc một số kí tự từ file f, và in ra chúng nếu chúng không phải là kí tự khoảng trắng

Một đối tượng file hoàn toàn chứa một dấu hiệu để mô tả vị trí hiện thời của con trỏ file.

Con trỏ file sẽ di chuyển từ đầu file, có thể dùng phương thức seek để dịch chuyển con trỏ file, ví dụ:

f.seek(0)

Các đối tượng file chuẩn:

Cũng giống như trong nhiều ngôn ngữ khác, các đối tượng file chuẩn được xây dựng sẵn để miêu tả vào, ra chuẩn và thông báo lỗi. Chúng nằm trong module sys và được gọi là stdin, stdout và stderr. Cũng có những bản sao của chúng trong __stdin__, __stdout__, và __stderr__. Được dành cho IDLE và các công cụ khác khi các file chuẩn đã thay đổi

Để sửdụng các stdin, stdout, stderr điều khiển vào ra cần file import module sys

Ví dụ đoạn mã sau sử dụng trong Python giống như lệnh cat trong UNIX

import sys

for line in sys.stdin:

print line,

Một đối tượng cũng quan trọng là mảng sys.argv. Đây là một mảng mà chứa các đối số dòng lệnh đến chương trình

python program.py hello there programmer!

Mảng này cũng có chỉ số và các đối số được định giá trị. Trong ví dụ trên, sys.argv[2] sẽ chứa xâu “there”, bởi vì tên của chương trình (“program.py”) được lưu trong argv[0]. Việc xử lý các đối số dòng lệnh có nhiều phức tạp hơn.

2. Output

Python sử dụng cách thức cơ bản nhất để xuất dữ liệu là dùng câu lệnh print.

print ‘Hello, world’

Để in ra nhiều thứ trên cùng một dòng, ta sử dụng dấu phẩy giữa chúng, ví dụ:

print ‘Hello,’, ‘World’

sẽ in ra như sau:

Hello, World

Chú ý rằng mặc dù xâu không chứa khoảng trống, nó cũng được thêm vào bởi lệnh print bởi vì dấu , giữa 2 đối tượng. Các kiểu dữ liệu tùy ý có thể được in theo cách này:

print 1,2,0xff,0777,(10+5j),-0.999,map,sys

sẽ in ra :

1 2 255 511 (10+5j) -0.999

Các đối tượng có thể in trên cùng một dòng không cần viết trên một dòng mà chỉ cần đặt một dấu , ở cuối của lệnh print

for i in range(10):

print i,

sẽ in ra:

0 1 2 3 4 5 6 7 8 9

Để kết thúc một dòng, cần thêm vào một lệnh print mà không có đối tượng nào, ví dụ:

for i in range(10):

print i,

print

for i in range(10,20):

print i,

sẽ in ra:

0 1 2 3 4 5 6 7 8 9

10 11 12 13 14 15 16 17 18 19

Nếu không có câu lệnh print trống thì nó sẽ in ra trên cùng một dòng

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

Nếu không muốn in một dòng mới hoặc một khoảng trống ( khi sử dụng dấu , ở cuối), ta có thể làm một điều khiển ngắn với sys.stdout.write và sử dụng để xuất ra:

import sys

write = sys.stdout.write

write(’20’)

write(’05\n’)

sẽ in ra:

2005

Những cú pháp như trên có thể sử dụng khi viết vào file thay vì đến thiết bị ra chuẩn, ví dụ:

print >> f, ‘Hello, world’

Cái này sẽ được in trong bất kì đối tượng nào mà thi hành hàm write() trong đó có đối tượng file.

II.7. Phạm vi (scope) và không gian tên (name space) trong Python

Trong Python sử dụng một tinh xảo phạm vi và không gian tên đối với các đối tượng của nó, để có thể hiểu đầy đủ về các kiểu cách đó, ta cần tìm hiểu về phạm vi và không gian tên.

1. Không gian tên:

Một không gian tên là một ánh xạ từ các tên đến các đối tượng, Hầu hết các không gian tên là được cung cấp như các từ điển Python, nhưng thông thường nó không được thông báo theo bất kì cách nào, và nó cũng có thể thay đổi trong tương lai. Ví dụ của không gian tên là: tập hợp các tên xây dựng sẵn, các tên toàn cục trong một module, các tên cục bộ trong một đăng kí hàm. Trong trường hợp nhạy cảm, tập các thuộc tính của một đối tượng cũng là một không gian tên. Điều quan trọng đối với không gian tên là không hề có sự liên hệ giữa các tên trong các khong gian tên giống nhau, ví dụ có 2 module khác nhau cùng định nghĩa một tên giống nhau thì không có gì khó khăn để sử dụng phân biệt 2 tên đó khi ta thêm tên của module vào đầu các tên đó.

Bằng cách như vậy ta sử dụng từ attribute cho bất cứ tên nào theo sau một dấu chấm. Ví dụ, trong biểu thức z.real, real là một thuộc tính của đối tượng z. Nói đúng ra, tham chiếu đến các tên trong các module là tham chiếu thuộc tính: sử dụng biểu thức modname.funcname, trong đó modname là tên của một đối tượng module, còn funcname là một thuộc tính của nó. Trong trường hợp này có một ánh xạ trực tiếp từ các thuộc tính của module và các tên toàn cục được định nghĩa trong module: chúng chia sẻ trong cùng một module.

Các thuộc tính có thể chỉ đọc hoặc có thể ghi. Trong trường hợp có thể ghi, cần phải đăng kí thuộc tính, các thuộc tính module có thể ghi, ta có thể viết “modname.the_answer = 42”. Các thuộc tính có thể ghi cũng có thể được loại bỏ với câu lệnh del. Ví dụ, “del modname.the_answer” sẽ loại bỏ thuộc tính the_answer từ đối tượng có tên là modname

Không gian tên tao ra tại các thời điểm khác nhau và có thời gian tồn tại cũng khác nhau. Không gian tên chứa các tên xây dựng sẵn được tạo ra khi trình thông dịch Python bắt đầu chạy và không bao giờ bị xóa đi. Không gian tên toàn cục do một module tạo ra khi định nghĩa module đó được đọc, thông thường không gian tên của module cũng tồn tại đến khi trình thông dịch kết thúc. Các câu lệnh thực hiện với yêu cầu cao nhất của trình thông dịch, hoặc đọc từ một file script hoặc tương tác với người sử dụng, được xem như là thành phần của một module gọi là __main__, vì thế chúng có một không gian tên toàn cục riêng (Các tên được xây dựng sẵn thực tế nằm trong một module, gọi là __builtin__)

Các không gian tên cục bộ của một hàm được tạo ra khi hàm đó được gọi, và bị xóa khi hàm đó trả về hoặc đưa ra một trường hợp mà không được điều khiển trong hàm đó. Tất nhiên các yêu cầu đệ qui cũng có không gian tên cục bộ của riêng nó.

2. Phạm vi

Một phạm vi là một vùng có liên quan trong một chương trình Python trong đó một không gian tên được truy nhập một cách trực tiếp. Truy nhập trực tiếp ở đây được hiểu là tham chiếu tuyệt đối đến một tên cố gắng tìm tên đó trong không gian tên.

Mặc dù các phamjv i được định nghĩa một cách cố định, nhưng chúng được sử dụng rất linh hoạt. Tại bất kì một thời điểm nào trong quá trình thực hiện, có ít nhất 3 phạm vi lồng nhau mà không gian tên của nó được truy nhập trực tiếp:

· Phạm vi trong cùng nhất được tìm kiếm đầu tiên chứa các tên cục bộ; không gian tên đó kết thúc khi bất kì hàm nào được kết thúc

· Phạm vi ở giữa, được tìm tiếp theo, chứa các tên toàn cục của module hiện tại

· Và phạm vi ngoài cùng, được tìm cuối cùng là chứa các không gian tên được xây dựng sẵn.

Nếu một tên được khai báo là toàn cục, thì tất cả các tham chiếu và đăng kí đều tìm trực tiếp vào không gian tên ở giữa (mức 2) chứa các tên toàn cục của module đó.

Thông thường, phạm vi cục bộ tham chiếu đến các tên của hàm hiện thời (trong phạm vi đó). Các hàm bên ngoài, phạm vi cục bộ tham chiếu đến các tên tương tự như phạm vi toàn cục: không gian tên của module đó. Các định nghĩa lớp lúc này đặt một không gian tên khác trong phạm vi cục bộ.

Cũng rất quan trọng để nhận ra các phạm vi: phạm vi toàn cục của một hàm được định nghĩa trong một module là không gian tên của module đó. Mặt khác, việc tìm kiếm các tên được thực hiện rất linh động.

Một điều đặc biệt của Python là việc đăng kí luôn luôn ở trong phạm vi trong cùng nhất. Việc đăng kí đó không sao chép dữ liệu mà chúng chỉ gắn các tên cho các đối tượng. Vì thế câu lệnh “del x” thực chất chỉ loại bỏ tên được gắn cho x từ không gian tên được tham chiếu bởi phạm vi cục bộ.

3. Các biến với phạm vi của nó trong Python

Các biến trong Python được tự động khai báo bằng cách đăng kí. Các biến luôn luôn tham chiếu đến các đối tượng và không bảo giờ cần phải định kiểu. Các biến chỉ tồn tại trong phạm vi hiện thời hoặc phạm vi tonaf cục. Khi ra khỏi phạm vi đó, các biến sẽ bị phá hủy, nhưng các đối tượng mà chúng tham chiếu thì không

Phạm vi được chỉ ra bởi các khối hàm và lớp. Cả các hàm và các phạm vi của chúng có thể lồng nhau, Vì thế:

def foo():

def bar():

x = 5 # x is now in scope

return x + y # y is defined in the enclosing scope later

y = 10

return bar() # now that y is defined, bar’s scope includes y

Chạy thử đoạn mã này

>>> foo()

15

>>> bar()

Traceback (most recent call last):

File “”, line 1, in -toplevelbar()

NameError: name ‘bar’ is not defined

Tên ‘bar’ không được tìm thấy bởi vì phạm vì cao hơn của nó không được truy nhập đến phạm vi thấp hơn trong thứ bậc đó. Đây cũng là một lỗi phổ biến làm hỏng các tìm kiến một thuộc tính (cũng như một phương thức) của một đối tượng (hay một cái chứa nó) được tham chiếu bởi một biến trước khi biến đó được đăng kí với đối tượng. Ví dụ:

>>> for x in range(10):

y.append(x) # append is an attribute of lists

Traceback (most recent call last):

File “”, line 2, in -toplevely.

append(x)

NameError: name ‘y’ is not defined

Ởđây, để chính xác phải có thêm y=[] trước vòng lặp.

II.8. Các kỹ thuật đặc biệt trong Python:

1. Quản lí lỗi:

Trong phần này, sẽ tìm hiểu về các cơ chế quản lí lỗi trong Python. Bao gồm các lỗi cú pháp và cơ chế dùng ngoại lệ (exception).

a. Lỗi cú pháp:

Bản chất là lỗi phân tích từ trong Python, đây có lẽ là lỗi phổ biến nhất của những người mới học lập trình Python. Một ví dụ lỗi đơn giản:

>>> while True print ‘Hello world’

File “”, line 1, in ?

while True print ‘Hello world’

^

SyntaxError: invalid syntax

Việc phân tích lặp lại trên các dòng mắc lỗi và hiện thị một con trỏ đầu tiên tại vị trí lỗi được dò ra (kiểu tương tự như pascal). Lỗi gây ra (được dò thấy đầu tiên) có dấu hiệu con trỏở trước, như trong ví dụ trên, lỗi dò thấy là tại từ khóa print, vì nó thiếu dấu hai chấm (“:”) ở trước. Tên file và số dòng cũng được in ra để có thể biết chính xác trong trường hợp đầu vào là một script.

b. Các ngoại lệ (Exception):

Mặc dù một câu lệnh hoặc một biểu thức là chính xác về cú pháp nhưng nó vẫn có thể gây ra lỗi khi chạy nó. Các lỗi dò được trong quá trình thực hiện được gọi là các ngoại lệ (exception) và không thể tránh khỏi tuyệt đối các lỗi này. Phần sau, sẽ tiếp tục nghiên cứu về cách điều khiển nó trong Python. Hầu hết các ngoại lệ đều không điều khiển được bởi chương trình, tuy nhiên các có thể chỉ ra các thông báo lỗi:

>>> 10 * (1/0)

Traceback (most recent call last):

File “”, line 1, in ?

ZeroDivisionError: integer division or modulo by zero

>>> 4 + spam*3

Traceback (most recent call last):

File “”, line 1, in ?

NameError: name ‘spam’ is not defined

>>> ‘2’ + 2

Traceback (most recent call last):

File “”, line 1, in ?

TypeError: cannot concatenate ‘str’ and ‘int’ objects

Dòng cuối cùng của thông báo lỗi cho biết chuyện gì đã xảy ra. Các ngoại lệ có nhiều kiểu khác nhau, và các kiểu này được in ở cuối thông báo lỗi. Trong ví dụ trên là:ZeroDivisionError, NameError và TypeError. Các xâu in ra là các kiểu ngoại lệ và tên của các ngoại lệ được xây dựng sẵn đưa ra. Điều này là được áp dụng cho tất cả các ngoại lệ cài sẵn, nhưng không áp dụng cho các ngoại lệ người sử dụng tự định nghĩa. Các tên ngoại lệ chuẩn các định danh có sẵn (không trùng với các từ khóa dành riêng).

Phần còn lại của thông báo cung cấp chi tiết dựa trên kiểu của ngoại lệ và nguyên nhân gây ra lỗi. Phần đặt trước thông báo lỗi chỉ ra ngữ cảnh ngoại lệ đó xảy ra, theo cơ chế dò lùi kiểu ngăn xếp. Tóm lại, nó chứa một danh sách các dòng nguồn, tuy nhiên có sẽ không hiển thị các dòng đọc từ đầu vào chuẩn.

c. Điều khiển các ngoại lệ:

Có thể viết các chương trình để điều khiển các ngoại lệ nào đó, Xem xét ví dụ dưới đây, yêu cầu người sử dụng nhập vào dữ liệu cho đến khi là số nguyên, nhưng cho phép người sử dụng ngắt chương trình (sử dụng CTRL + C hoặc tương tự do hệ điều hành hỗ trợ). Chú ý rằng các ngắt do người sử dụng tạo ra được nhận dạng bởi các ngoại lệ do ngắt bàn phím (KeyboardInterrupt exeption)

>>> while True:

… try:

… x = int(raw_input(“Please enter a number: “))

… break

… except ValueError:

… print “Oops! That was no valid number. Try again…”

Câu lệnh try hoạt động như sau:

Đầu tiên, mệnh đề try (câu lệnh giữa try và từ khóa except được thực hiện).
Nếu không có ngoại lệ nào xảy ra, mệnh đề except được bỏ qua và tiếp tục thực hiện try cho đến khi kết thúc.
Nếu có một ngoại lệ xảy ra trong khi đang thực hiện mệnh đề try thì phần còn lại của mệnh đề sẽ bị bỏ qua. Sau đó nếu như loại lỗi đó mà tương ứng với tên của ngoại lệ được đặt sau từ khóa except thì mệnh đề except sẽ được thực hiện, và sau đó tiếp tục thực hiện cho đến hết câu lệnh try.
Nếu một ngoại lệ xảy ra mà không tương ứng với ngoại lệ đã được đặt sau mệnh đề except thì nó sẽ bỏ qua thoát ra khỏi câu lệnh try. Nếu không có điều khiển nào được tìn thấy, thì đó một ngoại lệ không điều khiển và quá trình thực hiện kết thúc với một thông báo như đã chỉ ra ở trên.

Một câu lệnh try có thể có nhiều hơn một mệnh đề except, để xác định các điểu khiển cho các ngoại lệ khác nhau. Toàn bộ một điều khiển sẽ được thực hiện. Các điều khiển chỉ điều khiển các ngoại lệ xảy ra tương ứng với mệnh đề try. Một mệnh đề except có thể cỏ nhiều ngoại lệ theo sau được đặt trong dấu ngoặc đơn như một bộ, ví dụ:

… except (RuntimeError, TypeError, NameError):

… pass

Mệnh đề excpet cuối cùng có thể bỏ qua tên của ngoại lệ, để đáp ứng như một kí tự đại diện. Sử dụng điều này phải hết sức cẩn thận, bởi vì rất dễ bỏ qua một lỗi chương trình thực sự. Nó cũng có thể được sử dụng để in ra một thông báo lỗi và sau đó tái đề xuất ngoại lệ đó:

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 try… except có một mệnh đề else mở rộng, nó được xuất hiện sau tất cả các mệnh đề except. Nó được sử dụng để viết các đoạn mã mà chỉ thi hành khi mệnh đề try không gây ra một ngoại lệ nào. Ví dụ:

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()

Sử dụng mệnh đề else giúp ngăn ngừa được các ngoaik lệ gây ra bởi đoạn code nằm trong try…

Khi một ngoại lệ xảy ra, nó có thể có một giá trị liên quan, được gọi là đối số của ngoại lệ. Cách biểu diễn và kiểu của đối số đó phụ thuộc vào kiểu ngoại lệ. Mệnh đề except có thể xác định một biến theo sau tên ngoại lệ. Biến đó được gắn với một trường hợp ngoại lệ với các đối số được lưu trong instance.args. Để thuận tiện, trường hợp ngoại lệ đó định nghĩa __getitem__and__str__vì thế các đối số đó có thể được truy nhập hoặc đưa ra trực tiếp không cần tham chiếu .args

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

(‘spam’, ‘eggs’)

(‘spam’, ‘eggs’)

x = spam

y = eggs

Nếu một ngoại lệ có một đối số, nó được đưa ra như phần cuối cùng của một thông báo cho các ngoại lệ không điều khiển.

Các điều khiển ngoại lệ không chỉ điều khiển các ngoại lệ xảy ra ngay lập tức trong mệnh đề try, mà còn cho cả các lỗi xảy ra trong các hàm mà được gọi trong mệnh đề try. Ví dụ:

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

d. Đưa ra các ngoại lệ:

Câu lệnh raise cho phép người lập trình tác động đến một ngoại lệ xác định để cho nó xảy ra. Ví dụ:

>>> raise NameError, ‘HiThere’

Traceback (most recent call last):

File “”, line 1, in ?

NameError: HiThere

Đối số đầu tiên tạo ra các tên ngoại lệ sẽ được sinh ra. Đối số thứ hai xác định đối số của ngoại lệ đó. Một cách thay thế khác, câu lệnh ở trên có thể được viết lại. Nếu cần xác định một ngoại lệ được đưa ra nhưng không có ý định điều khiển nó, một dạng đơn giản của câu lệnh raise cho phép tái đưa ra một ngoại lệ:

>>> try:

… raise NameError, ‘HiThere’

… except NameError:

… print ‘An exception flew by!’

… raise

An exception flew by!

Traceback (most recent call last):

File “”, line 2, in ?

NameError: HiThere

e. Các ngoại lệ do người sử dụng định nghĩa:
Các chương trình có thể đặt tên ngoại lệ của chúng bằng cách tạo ra một lớp ngoại lệ mới. Các ngoại lệ thông thường được thừa kế từ lớp Exception, hoặc là kế thừa trực tiếp hoặc không trực tiếp. Ví dụ:

>>> 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 “”, line 1, in ?

__main__.MyError: ‘oops!’

Trong ví dụ này, phương thức mặc định __init__ của lớp Exception bị ghi chèn lên. Một thuộc tính giá trị mới được tạo ra, nó sẽ thay thế cách thức mặc định tạo ra thuộc tính args.

Các lớp ngoại lệ có thể được định nghĩa để làm bất cứ điều gì như các lớp thông thường, nhưng thường là nó được xây dựng rất đơn giản, nó chỉ đưa ra một số các thuộc tính thông tin về các lỗi được lấy ra từ bởi các điều khiển đối với các ngoại lệ. Khi tạo ra một module mà có thể gây ra một vài lỗi phân biệt, một thói quen phổ biến là tạo ra một lớp cơ sở cho các ngoại lệ được định nghĩa bởi module đó, và lướp con để tạo ra các lớp ngoại lệ cụ thể cho các điều kiện 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

Hầu hết các ngoại lệ do người sử dụng tạo ra được định nghĩa với các tên mà kết thúc là ‘Error’ giống với tên của các ngoại lệ chuẩn.

Nhiều module chuẩn định nghĩa các ngoại lệ của riêng nó để thông báo các lỗi có thể xảy ra trong các hàm mà chúng định nghĩa.

2. Quản lí bộ nhớ:

Pyhton có một cơ chế tự động quản lý bộ nhớ (đếm số lần tham chiếu của hầu hết các đối tượng và tập hợp không hợp lệ để loại trừ chúng theo chu kì). Bộ nhớ sẽ được giải phóng ngay sau khi tham chiếu cuối cùng tới nó được loại bỏ.

II.9. Lập trình giao diện:

Có khá nhiều các bộ lập trình giao diện với Python. Sau đây ta sẽ tìm hiểu tổng quan về chúng.

1. Tkinter:

Đây là một công cụ lập trình giao diện Python cho Tcl/Tk, được đưa vào Python (chạy trên nền Win32 mặc dù nó có thể được cài trên Unix/Linux hoặc Mac) và cung cấp một giao diện người sử dụng. Không phải là đơn giản để học cách sử dụng bộ công cụ mạnh này, nó cung cấp những thứ xuất hiện như là một tập hợp các cửa sổ. Tuy nhiên, bởi vì các cửa sổ Tkinter có thể mở rộng, nhiều cửa sổ được tạo ra khá dễ dàng. Tkinter được thiết kế như là một giao diện người sử dụng do yêu cầu thực tế cho Python.

Để tạo ra một một khung cửa sổ đơn giản trong Tkinter chỉ cần làm như đoạn code sau:

import Tkinter

root = Tkinter.Tk()

root.mainloop()

gfd From an object-oriented perspective one can do the following:

import Tkinter

class App:

def __init__(self, master):

button = Tkinter.Button(master, text=”I’m a Button.”)

button.pack()

if __name__ == ‘__main__’:

root = Tkinter.Tk()

app = App(root)

root.mainloop()

Các site cung cấp thông tin về Tkinter

• http://www.astro.washington.edu/owen/TkinterSummary.html <- A summary

• http://infohost.nmt.edu/tcc/help/lang/python/tkinter.html <- A tutorial

• http://www.pythonware.com/library/tkinter/introduction/ <- A reference

2. PyGTK

PyGTK cung cấp một công cụ thuận tiện cho GTK cộng với các thư viện sử dụng trong các chương trình Python. Quan tâm đến nhiều chi tiết như quan lí bộ nhớ và thay thế. Khi kết hợp với PyORBit và gnome-python, nó có thể được sử dụng để viết các ứng dụng Gnome với đầy đủ các đặc điểm.

3. PyQt:

Sử dụng phổ biến trên Unix/Linux và các bộ công cụ Windows. PyKDE có thể được sử dụng để viết các ứng dụng dựa trên KDE.

4. wxPython

Gắn với bộứng dụng wxWidgets, nó có thể chạy trên Windows, Macintosh, và Unix/Linux.

Tài liệu tham khảo:

1. Python Documentation

2. Python_Programming.pdf

3. website: http://www.python.org

4. website: http://en.wikipedia.org/wiki/Python_programming_language

5. website: http://pythonnet.sourceforge.net/readme.html

Advertisement

Share this:

Thích bài này:

Thích

Đang tải…