học python

59
PDF được tạo bằng bộ công cụ mã nguồn mở mwlib. Xem http://code.pediapress.com/ để biết thêm thông tin. PDF generated at: Thu, 28 Aug 2014 06:53:15 UTC Học Python

Upload: tung-nguyen-xuan

Post on 20-Jun-2015

570 views

Category:

Education


3 download

DESCRIPTION

học Python- tổng hợp từ wikibook

TRANSCRIPT

Page 1: Học python

PDF được tạo bằng bộ công cụ mã nguồn mở mwlib. Xem http://code.pediapress.com/ để biết thêm thông tin.PDF generated at: Thu, 28 Aug 2014 06:53:15 UTC

Học Python

Page 2: Học python

Nội dungBài

Chương I 1Chương II 14Chương III 17Chương IV 29Chương V 39Bài tập căn bản 48

Chú thíchNguồn và người đóng góp vào bài 55Nguồn, giấy phép, và người đóng góp vào hình 56

Giấy phép Bài viếtGiấy phép 57

Page 3: Học python

Chương I 1

Chương I

Python trên FreeBSD 7.0-Trên FreeBSD có hổ trợ Python-2.4 và Python-2.5. Bạn có thể cài đặt từ mã nguồn•• Cài đặt Python 2.4

# cd /usr/ports/lang/python24

# make install clean

# python2.4

Python 2.4.4 (#2, Dec 7 2007, 13:41:55)

[GCC 3.4.6 [FreeBSD] 20060305] on freebsd6

Type "help", "copyright", "credits" or "license" for more information.

>>>

•• Cài đặt Python 2.5

# cd /usr/ports/lang/python25

# make install clean

# python2.5

Python 2.5.1 (r251:54863, Dec 2 2007, 06:39:44)

[GCC 3.4.6 [FreeBSD] 20060305] on freebsd6

Type "help", "copyright", "credits" or "license" for more information.

>>>

Thoát khỏi python ta dùng CTRL+D-Cài đặt python từ mã nguồn Nếu bạn thích cài từ source, bạn có thể download python source code từ đây [1]. Chọnversion cao nhất trong danh sách và download file có đuôi .tgz, sau đó dùng các lệnh configure, make, make install.-Ví dụ install từ mã nguồn

# wget http:/ / www. python. org/ ftp/ python/ 2. 5/ Python−2. 5. tgz

Resolving www.python.org... done.

Connecting to www.python.org[194.109.137.226]:80... connected.

HTTP request sent, awaiting response... 200 OK

Length: 8,436,880 [application/x−tar]...

# tar xfz Python−2.5.tgz# cd Python−2.5# ./configure

checking MACHDEP... linux2

checking EXTRAPLATDIR...

checking for −−without−gcc... no...

# make

gcc −pthread −c −fno−strict−aliasing −DNDEBUG −g −O3 −Wall −Wstrict−prototypes−I. −I./Include −DPy_BUILD_CORE −o Modules/python.o Modules/python.cgcc −pthread −c −fno−strict−aliasing −DNDEBUG −g −O3 −Wall −Wstrict−prototypes−I. −I./Include −DPy_BUILD_CORE −o Parser/acceler.o Parser/acceler.cgcc −pthread −c −fno−strict−aliasing −DNDEBUG −g −O3 −Wall −Wstrict−prototypes

Page 4: Học python

Chương I 2

−I. −I./Include −DPy_BUILD_CORE −o Parser/grammar1.o Parser/grammar1.c...

# make install

/usr/bin/install −c python /usr/local/bin/python2.5...

# python

Python 2.5.1 (#2, Sep 24 2003, 11:39:14)

[GCC 3.3.2 20030908 (Debian prerelease)] on linux2

Type "help", "copyright", "credits" or "license" for more information.

>>> [press Ctrl+D to get back to the command prompt]

#

Làm việc trên cửa sổ ShellBây giờ bạn đã cài xong python, có nhưng tác động gì cửa sổ dòng lệnh shell khi bạn chạy nó?Python nắm hai vai trò. Nó biên dịch cho script để bạn có thể chạy từ command line hoặc chạy như các ứng dụng,bằng cách double−clicking scripts. Nhưng nó cũng làm việc được ở cửa sổ dòng lệnh shell để bạn có thể đánh giá tuyý các thành phần và những sự diễn đạt. Đây là cái vô cùng hữu dụng cho việc debug, quick hacking, và kiểm tra. Tôicòn biết vài người dùng python thay cho máy tính bỏ túi•• Ví dụ:

>>> 1 + 1 (1)

2

>>> print 'hello world'

hello world (2)

>>> x = 1

>>> y = 2

>>> x + y

3 (3)

(1)Python có thể tính toán các bài toán dơn giản,(2)python có thể in ra màn hình,(3)Bạn cũng có thể gán và khai báo các biến.

Page 5: Học python

Chương I 3

Viết Python Bằng EclipseEclipse có trong ports của FreeBSD để cài Eclipse bạn làm như sau:

# cd /usr/ports/java/eclipse

# make install clean

Sau khi cài xong bạn khởi động Eclipse bằng dòng lệnh # eclipse sẽ xuất hiện như hình dưới đây:

Sau khi eclipse khởi động xong bạn bắt đầu install Pydev theo hướng dẫn sau:• Bạn vào link sau để download gói pydev phiên bản mới nhất, và giải nén file(Download [2]):

# unzip org.python.pydev.feature-1_3_11.zip

Sau khi giải nén sẽ cho ra thư mục eclipse trong đó có 2 thư mục

features và plugins, bạn chép tất cả các file và thư mục có trong 2 thư

mục trên vào nơi mà bạn đã cài eclipse. Cách làm như sau:

# cp -r eclipse/features/org.python.pydev.feature_1.3.11

/usr/local/eclipse/features

# cd eclipse/plugins/

# cp -rf * /usr/local/eclipse/plugins

•• Bạn khởi động eclipse và tiến hành cài pydev như sau:

Page 6: Học python

Chương I 4

Bạn chọn menu Window --> Preferences...

Tiếp theo bạn chọn Pydev-->Interpreter-Python. Chọn New và chọn file chạy Python2.5, chọn ok

Page 8: Học python

Chương I 6

Sau khi tạo Project xong bạn click phải vào project bạn vừa tạo để tạo file, cách làm như sau:

Sau khi điền tên file xong bạn chon Finish. Đến đây bạn đã tạo xong file để viết chương trình. Sau đây la ví dụ vềcách viết trên một chương trình giải phương trình bậc 2 trên eclipse bằng ngôn ngữ Python:

Page 9: Học python

Chương I 7

Để chạy chương trình bạn click phải vào vùng viết code và chon Run as --> Python run

Kết quả sẽ được hiện thị như sau :

Page 10: Học python

Chương I 8

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

>>> 'welcome'

'welcome'

>>> 'doesn\'t'

"doesn't"

>>> "doesn't"

"doesn't"

>>> '"Chao," cac ban.'

'"Chao," cac ban.'

>>> "\"Chao,\" cac ban."

'"Chao," cac ban.'

>>> '"Isn\'t," she said.'

'"Isn\'t," she said.'

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

hello = "This is a rather long string containing\n\

several lines of text just as you would do in C.\n\

Note that whitespace at the beginning of the line is\

significant."

print hello

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

This is a rather long string containing

several lines of text just as you would do in C.

Note that whitespace at the beginning of the line is significant.

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

Page 11: Học python

Chương I 9

Cho nên, ví dụ:

hello = r"This is a rather long string containing\n\

several lines of text much as you would do in C."

print hello

sẽ in:

This is a rather long string containing\n\

several lines of text much as you would do in C.

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

print """

Usage: thingy [OPTIONS]

-h Display this usage message

-H hostname Hostname to connect to

"""

xuất ra:

Usage: thingy [OPTIONS]

-h Display this usage message

-H hostname Hostname to connect to

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

>>> word = 'Help' + 'A'

>>> word

'HelpA'

>>> '<' + word*5 + '>'

'<HelpAHelpAHelpAHelpAHelpA>'

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

>>> 'str' 'ing' # <- This is ok

'string'

>>> 'str'.strip() + 'ing' # <- This is ok

'string'

>>> 'str'.strip() 'ing' # <- This is invalid

File "<stdin>", line 1, in ?

'str'.strip() 'ing'

^

Page 12: Học python

Chương I 10

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

>>> word[4]

'A'

>>> word[0:2]

'He'

>>> word[2:4]

'lp'

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

>>> word[:2] # The first two characters

'He'

>>> word[2:] # Everything except the first two characters

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

>>> word[0] = 'x'

Traceback (most recent call last):

File "<stdin>", line 1, in ?

TypeError: object doesn't support item assignment

>>> word[:1] = 'Splat'

Traceback (most recent call last):

File "<stdin>", line 1, in ?

TypeError: object doesn't support slice assignment

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

>>> 'x' + word[1:]

'xelpA'

>>> 'Splat' + word[4]

'SplatA'

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

>>> word[:2] + word[2:]

'HelpA'

>>> word[:3] + word[3:]

'HelpA'

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

>>> word[1:100]

'elpA'

>>> word[10:]

Page 13: Học python

Chương I 11

>>> word[2:1]

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

>>> word[-1] # The last character

'A'

>>> word[-2] # The last-but-one character

'p'

>>> word[-2:] # The last two characters

'pA'

>>> word[:-2] # Everything except the last two characters

'Hel'

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

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

'H'

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

>>> word[-100:]

'HelpA'

>>> word[-10] # error

Traceback (most recent call last):

File "<stdin>", line 1, in ?

IndexError: string index out of range

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

+---+---+---+---+---+

| H | e | l | p | A |

+---+---+---+---+---+

0 1 2 3 4 5

-5 -4 -3 -2 -1

Các số hàng đầu cho biết vị trí của các chỉ mục 0...5 trong chuỗi; dòng thứ hai cho biết các chỉ mục âm tương ứng.Một lát từ i tới j chứa toàn bộ các ký tự giữa các cạnh đánh số i và jtương ứng.Với các chỉ mục không âm, chiều dài của lát là hiệu của các chỉ mục, nếu cả hai đều trong giới hạn. Ví dụ, độ dài củaword[1:3] là 2.Hàm có sẵn len() trả về độ dài của một chuỗi:

>>> s = 'supercalifragilisticexpialidocious'

>>> len(s)

34

Page 14: Học python

Chương I 12

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

>>> a = ['hallo', 'good', 100, 1234]

>>> a

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

>>> a[0]

'hallo'

>>> a[3]

1234

>>> a[-2]

100

>>> a[1:-1]

['good', 100]

>>> a[:2] + ['bacon', 2*2]

['hallo', 'good', 'bacon', 4]

>>> 3*a[:3] + ['Boo!']

['hallo', 'good', 100, 'hallo', 'good', 100, 'hallo', 'good', 100, 'Boo!']

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

>>> a

['hallo', 'good', 100, 1234]

>>> a[2] = a[2] + 23

>>> a

['hallo', 'good', 123, 1234]

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

>>> # Replace some items:

... a[0:2] = [1, 12]

>>> a

[1, 12, 123, 1234]

>>> # Remove some:

... a[0:2] = []

>>> a

[123, 1234]

>>> # Insert some:

... a[1:1] = ['bletch', 'xyzzy']

>>> a

[123, 'bletch', 'xyzzy', 1234]

>>> # Insert (a copy of) itself at the beginning

>>> a[:0] = a

>>> a

[123, 'bletch', 'xyzzy', 1234, 123, 'bletch', 'xyzzy', 1234]

Page 15: Học python

Chương I 13

>>> # Clear the list: replace all items with an empty list

>>> a[:] = []

>>> a

[]

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

>>> len(a)

8

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

>>> q = [2, 3]

>>> p = [1, q, 4]

>>> len(p)

3

>>> p[1]

[2, 3]

>>> p[1][0]

2

>>> p[1].append('xtra') # See section 5.1

>>> p

[1, [2, 3, 'xtra'], 4]

>>> q

[2, 3, 'xtra']

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

Chú thích[1] http:/ / www. python. org/ ftp/ python/[2] http:/ / sourceforge. net/ project/ showfiles. php?group_id=85796& package_id=88954& release_id=568546

Page 16: Học python

Chương II 14

Chương II

Đi vào PythonPython hầu như chắc chắn không tạo ra sự cảm hứng nhất định đến bạn. Đừng lo lắng về điều đó, bởi vì bạn sẽ phảiphân tích nó, nghiên cứu thông qua nó trước và thấy gì, bạn có thể hiểu được nó.•• Ví dụ:odbchelper.pyNếu bạn chưa sản sàng để làm, bạn có thể tham khảo ví dụ dưới đây:

def buildConnectionString(params):

"""Build a connection string from a dictionary of parameters.

Returns string."""

return ";".join(["%s=%s" % (k, v) for k, v in params.items()])

if __name__ == "__main__":

myParams = {"server":"mpilgrim", \

"database":"master", \

"uid":"sa", \

"pwd":"secret" \

}

print buildConnectionString(myParams)

Bây giờ chạy chương trình bạn sẽ thấy điều gì.Trong UNIX(bao gồm Mac OS X), bạn có thể chạy chương trình python từ command line:

#python odbchelper.py

odbchelper.py sẽ in ra màn hình như sau:

server=mpilgrim;uid=sa;database=master;pwd=secret

Khai báo hàmPython có các hàm như những ngôn ngữ khác, nhưng nó không có các gói file riêng biệt như C++ hoặc các đoạninterface/implementation như Pascal. Khi bạn cần một hàm, chỉ việc khai báo nó, như thế này:

def buildConnectionString(params):

Chú ý rằng khi đánh def bắt đầu khai báo một hàm, được theo tên hàm, theo những gì được gán trong dấu ngoặc đơn.Cũng chú ý rằng hàm không định nghĩa một kiểu dữ liệu trả về. Hàm của Python không định rõ kiểu dữ liệu củanhững giá trị trả về, chúng cũng không định rõ một giá trị được trả về hay không. Trong thực tế, những hàm pythontrả về một giá trị, nếu hàm có chỉ ra thực hiện những chỉ dẫn một thông báo trả về, nó sẽ trả về giá trị đó, nếu khôngthì nó sẽ trả về một giá trị rỗng.

Page 17: Học python

Chương II 15

Làm thế nào để so sánh kiểu dữ liệu của python và các ngôn ngữ lập trình khác•• Kiểu ngôn ngữ tĩnhNó không tự hình thành cho mình một xử lý chuyên phía dưới, nó phải dựa vào những nền tảng của những ngôn ngữkhác như java và C để tạo cho mình lớp bọc phía trên•• Kiểu ngôn ngữ năng độngMột ngôn ngữ mà các kiểu được tìm ra như thời gian thi hành, trái với ngôn ngữ tĩnh. VBScript và Python là kiểunăng động, vì chúng mang một dáng vẽ bên ngoài có thể thay đổi được khi bạn đầu tiên gán cho nó một giá trị.•• Kiểu ngôn ngữ mạnh mẽMột ngôn ngữ mà trong đó các kiểu luôn được tuân theo. Java và Python là 2 kiểu mạnh mẽ. Nếu bạn có một kiểuinteger, bạn không thể coi nó như một kiểu string mà không có sự chuyển đổi rõ ràng.•• Kiểu ngôn ngữ thấpMột ngôn ngữ mà trong đó các kiểu này có thể bị loại bỏ, trái ngược với kiểu mạnh mẽ. VBScript là kiểu thấp. TrongVBScript, bạn có thể nối string '12' với integer 3 để được string '123', sau đó coi như integer 123, tất cả đều khôngcần đến sự chuyển đổi rõ ràng.Vì vậy Python vừa là kiểu ngôn ngữ năng động vừa là kiểu ngôn ngữ mạnh mẽ.

Chứng minh các hàmBạn có thể chứng minh một hàm trong python bằng cách cho nó một kiểu dữ liệu chuỗi.•• Ví dụ:

def buildConnectionString(params):

"""Build a connection string from a dictionary of parameters.

Returns string."""

Ba dấu ngoặc kép có nghĩa là một chuỗi đa dòng. Mọi thứ bắt đầu và kết thúc các dấu ngoặc kép là đường dẫn củamột chuỗi đơn, bao gồm thi hành việc trả về vá những ký tự nằm giữa dấu ngoặc kép khác. Bạn có thể dùng chúngbất cứ đâu, nhưng bạn sẽ thấy chúng hầu như thường được dùng để dịnh nghĩa một kiểu dữ liệu chuỗi.Ba dấu ngoặc kép cũng là cách để định nghĩa một chuỗi với một và 2 dấu ngoặ kép. Những gì giữa 3 dấu ngoặ kép làkiễu dữ liệu chuỗi của hàm, những dữ liệu nào dùng hàm gì. Một dữ liệu chuỗi, nếu nó đã tồn tại, điều trước tiênphải được định nghĩa trong một hàm. Bạn không cần ngữ nghĩa cho một hàm của bạn, nhưng bạn luôn cấn đến. Đâyla việ khó khăn, nhưng python sẽ cho bạn một sự khích lệ: dữ liệu chuỗi có thể dùng được ở chế độ làm việc như mộtthuộc tính của hàm.

Mọi thứ là một đối tượngHàm trong Python có các thuộc tính, và các thuộc tính đó có thể dùng được ở chế độ làm việc.Một hàm, như những thứ khác trong Python, là một đối tượng.•• Ví dụ:

>>> import odbchelper (1)

>>> params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"}

>>> print odbchelper.buildConnectionString(params) (2)

server=mpilgrim;uid=sa;database=master;pwd=secret

>>> print odbchelper.buildConnectionString.__doc__ (3)

Build a connection string from a dictionary

Returns string.

Page 18: Học python

Chương II 16

(1) Dòng đầu tiên import odbchelper như một module--một đoạn của code mà bạn có thể dùng cách tương tác. hoặctừ một ngôn ngữ Python lớn. Một lần bạn import một module, bạn có thể tham chiếu bất cứ các hàm, các lớp, hoặccác thuộc tính. Các Module có thể làm điều này để nhập thuộc tính về hàm trong các module khác. Đây là một kháiniệm quan trọng bạn sẽ nói nhiều về nó sau này.(2) Khi bạn muốn dùng hàm được định nghĩa trong import module, bạn cần bao gồm cả tên module. Ví vậy bạnkhông thể chỉ gọi buildConnectionString, nó phải là odbchelper.buildConnectionString. Nếu bạn đã từng dùng cáclớp trong java, điều này sẽ có cảm giác hơi quen thuộc.(3)Thay vì gọi một hàm như bạn mong đợi, bạn được hỏi các thuộc tính của hàm __doc__. Import python như ngônngữ perl. Một lần bạn import module python. Bạn xác nhận hàm của nó với module.function. Một lần bạn dùng hàmPerl, bạn xác nhận hàm của nó với module::function.

Nhập tìm đường dẫnTrước khi tiếp tục, tôi muốn đề cấp ngắn gọn về thư viện tìm đường dẫn. Python tìm kiếm trong những nơi bạnimport một module. Một cách cụ thể, nó tìm kiếm trong tất cả các thư mục được định nghĩa trong sys.path. Đây làmột danh sách, và bạn có thể dễ dàng xem hoạc thay đổi nó theo theo thứ tự.•• Ví dụ:

>>> import sys (1)

>>> sys.path (2)

[, '/usr/local/lib/python2.2', '/usr/local/lib/python2.2/plat−linux2','/usr/local/lib/python2.2/lib−dynload', '/usr/local/lib/python2.2/site−packages','/usr/local/lib/python2.2/site−packages/PIL', '/usr/local/lib/python2.2/site−packages/piddle']>>> sys (3)

<module 'sys' (built−in)>>>> sys.path.append('/my/new/path') (4)

(1)Nhập sys module tạo cho tất cả các hàm và các thuộc tính của nó có thể dùng được.(2) sys.path là một danh sách các tên mà tạo ra một luồng tìm kiếm đường dẫn. Python sễ tìm kiếm các thư mục bêntrong có các file .py kết hợp với tên module bạn đã import.(3) Trên thực tế nó còn rắc rối hơn thế nhiều, bởi vì không có tất cả module đã được dự trữ như các file .py . Như sysmodule được thiết lập trong các module.(4) Bạn có thể thêm một thư mục mới để tìm kiếm đường dẫn trong python có thể làm việc được băng cách gán thêmvào tên thư mục đến sys.path, sau đó python sẽ tìm kiếm trong thư mục đó.

Đối tượng là gì?Mọi thứ trong python là một đối tượng, và hầu như mọi thứ đề có thuộc tính và phương pháp. Tất cả các hàm thiếtlập trong thuộc tính __doc__, trã về dữ liệu chuỗi được định nghĩa trong mã nguồn của hàm. Sys module là một đốitượng mà có một thuộc tính được gọi là path. Và tương tự như thế.Các ngôn ngữ lập trình khác định nghĩa đối tượng theo nhưng cách khác nhau. Ý nghĩa của nó là tất cả các đối tượngbuộc phải có các thuộc tính và các phương thức, mặc khác, nó có nghĩa là tất cả các đối tượng phân lớp được. TrongPython, định nghĩ đó là sai, một số các đối tượng hoặc là các thuộc tính hoặc là các phương thức, và không có đốitượng nào phân lớp được. Nhưng tất cả là một hướng đối tượng mà nó có thể được gán một sự biến thiên hoặc đượcthông qua như một đối số đến một hàm.Điều này đặc biệt quan trọng , mọi thứ trong python đều là đối tượng. Chuỗi là các đối tượng, Danh sách là các đốitượng, Hàm là các đối tượng, mudule cũng là các đối tượng.

Page 19: Học python

Chương III 17

Chương IIIKhái niệm hướng đối tượng được xây dựng trên nền tảng của khái niệm lập trình có cấu trúc và sự trừu tượng hóa dữliệu. Sự thay đổi căn bản ở chỗ, một chương trình hướng đối tượng được thiết kế xoay quanh dữ liệu mà chúng ta cóthể làm việc trên đó, hơn là theo chính chức năng của chương trình. Điều này hoàn toàn tự nhiên một khi chúng tahiểu rằng mục tiêu của chương trình là xử lý dữ liệu. Suy cho cùng, công việc mà máy tính thực hiện vẫn thườngđược gọi là xử lý dữ liệu. Dữ liệu và thao tác liên kết với nhau ở một mức cơ bản (còn có thể gọi là mức thấp), mỗithứ đều đòi hỏi ở thứ kia có mục tiêu cụ thể, các chương trình hướng đối tượng làm tường minh mối quan hệ này.Lập trình hướng đối tượng (Object Oriented Programming-OOP) hay chi tiết hơn là Lập trình định hướng đối tượng,chính là phương pháp lập trình lấy đối tượng làm nền tảng để xây dựng thuật giải, xây dựng chương trình. Thực chấtđây không phải là một phương pháp mới mà là một cách nhìn mới trong việc lập trình. Để phân biệt, với phươngpháp lập trình theo kiểu cấu trúc mà chúng ta quen thuộc trước đây, hay còn gọi là phương pháp lập trình hướng thủtục, người lập trình phân tích một nhiệm vụ lớn thành nhiều công việc nhỏ hơn, sau đó dần dần chi tiết, cụ thể hoá đểđược các vấn đề đơn giản, để tìm ra cách giải quyết vấn đề dưới dạng những thuật giải cụ thể rõ ràng qua đó dễ dàngminh hoạ bằng ngôn ngữ giải thuật. Cách thức phân tích và thiết kế như vậy chúng ta gọi là nguyên lý lập trình từtrên xuống, để thể hiện quá trình suy diễn từ cái chung cho đến cái cụ thể.Các chương trình con là những chức năng độc lập, sự ghép nối chúng lại với nhau cho chúng ta một hệ thống chươngtrình để giải quyết vấn đề đặt ra. Chính vì vậy, cách thức phân tích một hệ thống lấy chương trình con làm nền tảng,chương trình con đóng vai trò trung tâm của việc lập trình, được hiểu như phương pháp lập trình hướng về thủ tục.Tuy nhiên, khi phân tích để thiết kế một hệ thống không nhất thiết phải luôn luôn suy nghĩ theo hướng “làm thế nàođể giải quyết công việc”, chúng ta có thể định hướng tư duy theo phong cách “với một số đối tượng đã có, phải làmgì để giải quyết được công việc đặt ra” hoặc phong phú hơn, “làm cái gì với một số đối tượng đã có đó”, từ đó cũngcó thể giải quyết được những công việc cụ thể. Với phương pháp phân tích trong đó đối tượng đóng vai trò trung tâmcủa việc lập trình như vậy.Lập trình hướng đối tượng liên kết cấu trúc dữ liệu với các thao tác, theo cách mà tất cả thường nghĩ về thế giớiquanh mình. Chúng ta thường gắn một số các hoạt động cụ thể với một loại hoạt động nào đó và đặt các giả thiết củamình trên các quan hệ đó.Lập trình hướng đối tượng cho phép chúng ta sử dụng các quá trình suy nghĩ như vậy với các khái niệm trừu tượngđược sử dụng trong các chương trình máy tính. Một mẫu tin nhân sự có thể được đọc ra, thay đổi và lưu trữ lại; cònsố phức thì có thể được dùng trong các tính toán. Tuy vậy không thể nào lại viết một số phức vào tập tin làm mẫu tinnhân sự và ngược lại hai mẫu tin nhân sự lại không thể cộng với nhau được. Một chương trình hướng đối tượng sẽxác định đặc điểm và hành vi cụ thể của các kiểu dữ liệu, điều đó cho phép chúng ta biết một cách chính xác rằngchúng ta có thể có được những gì ở các kiểu dữ liệu khác nhau.Chúng ta còn có thể tạo ra các quan hệ giữa các kiểu dữ liệu tương tự nhưng khác nhau trong một chương trìnhhướng đối tượng. Người ta thường tự nhiên phân loại ra mọi thứ, thường đặt mối liên hệ giữa các khái niệm mới vớicác khái niệm đã có, và thường có thể thực hiện suy diễn giữa chúng trên các quan hệ đó. Hãy quan niệm thế giớitheo kiểu cấu trúc cây, với các mức xây dựng chi tiết hơn kế tiếp nhau cho các thế hệ sau so với các thế hệ trước. Đâylà phương pháp hiệu quả để tổ chức thế giới quanh chúng ta. Các chương trình hướng đối tượng cũng làm việc theomột phương thức tương tự, trong đó chúng cho phép xây dựng các các cơ cấu dữ liệu và thao tác mới dựa trên các cơcấu có sẵn, mang theo các tính năng của các cơ cấu nền mà chúng dựa trên đó, trong khi vẫn thêm vào các tính năngmới. Lập trình hướng đối tượng cho phép chúng ta tổ chức dữ liệu trong chương trình theo một cách tương tự như cácnhà sinh học tổ chức các loại thực vật khác nhau. Theo cách nói lập trình đối tượng, xe hơi, cây cối, các số phức, cácquyển sách đều được gọi là các lớp (Class).Một lớp là một bản mẫu mô tả các thông tin cấu trúc dữ liệu, lẫn các thao tác hợp lệ của các phần tử dữ liệu. Khi mộtphần tử dữ liệu được khai báo là phần tử của một lớp thì nó được gọi là một đối tượng (Object). Các hàm được định

Page 20: Học python

Chương III 18

nghĩa hợp lệ trong một lớp được gọi là các phương thức (Method) và chúng là các hàm duy nhất có thể xử lý dữ liệucủa các đối tượng của lớp đó. Một thực thể (Instance) là một vật thể có thực bên trong bộ nhớ, thực chất đó là mộtđối tượng (nghĩa là một đối tượng được cấp phát vùng nhớ).Mỗi một đối tượng có riêng cho mình một bản sao các phần tử dữ liệu của lớp còn gọi là các biến thực thể (Instancevariable). Các phương thức định nghĩa trong một lớp có thể được gọi bởi các đối tượng của lớp đó. Điều này đượcgọi là gửi một thông điệp (Message) cho đối tượng. Các thông điệp này phụ thuộc vào đối tượng, chỉ đối tượng nàonhận thông điệp mới làm việc theo thông điệp đó. Các đối tượng đều độc lập với nhau vì vậy các thay đổi trên cácbiến thể hiện của đối tượng này không ảnh hưởng gì trên các biến thể hiện của các đối tượng khác và việc gửi thôngđiệp cho một đối tượng này không ảnh hưởng gì đến các đối tượng khác.Như vậy, đối tợng được hiểu theo nghĩa là một thực thể mà trong đó các dữ liệu và thủ tục tác động lên dữ liệu đãđược đóng gói lại với nhau. Hay “đối tượng được đặc trưng bởi một số thao tác (operation) và các thông tin(information) ghi nhớ sự tác động của các thao tác này.Các thao tác trong đối tượng được gọi là các phương thức hay hành vi của đối tượng đó. Phương thức và dữ liệu củađối tượng luôn tác động lẫn nhau và có vai trò ngang nhau trong đối tượng, Phương thức của đối tượng được qui địnhbởi dữ liệu và ngược lại, dữ liệu của đối tượng được đặt trưng bởi các phương thức của đối tượng. Chính nhờ sự gắnbó đó, chúng ta có thể gởi cùng một thông điệp đến những đối tượng khác nhau. Điều này giúp người lập trình khôngphải xử lý trong chương trình của mình một dãy các cấu trúc điều khiển tuỳ theo thông điệp nhận vào, mà chươngtrình được xử lý vào thời điểm thực hiện.Tóm lại, so sánh lập trình cấu trúc với chương trình con làm nền tảng:Chương trình = Cấu trúc dữ liệu + Thuật giảiTrong lập trình hướng đối tượng chúng ta có: Đối tượng = Phương thức + Dữ liệuĐây chính là 2 quan điểm lập trình đang tồn tại và phát triển trong thế giới ngày nay.

ClassChỉ cần một ít cú pháp và từ khóa mới, Python đã có thể hỗ trợ class. Nó là sự trộn lẫn giữa C++ và Modula-3. Cũngnhư module, các lớp trong Python không đặt rào cản tuyệt đối giữa định nghĩa lớp và người sử dụng, mà thay vào đónó dựa vào sự lịch thiệp trong cách dùng mà ``không phá định nghĩa. Tuy nhiên, các tính năng quan trọng nhất củaclass vẫn được giữ lại trọn vẹn: cách kế thừa class hỗ trợ nhiều class cơ sở, class con có thể định nghĩa lại bất kỳphương thức nào của các class cơ sở của nó, và một phương thức có thể gọi một phương thức cùng tên của mộtclass cơ sở. Các đối tượng có thể chứa một lượng dũ liệu riêng bất kỳ.

Theo thuật ngữ C++, mọi thành viên class (kể cả thành viên dữ liệu) là public(công cộng), và mọi thành viên hàm làvirtual(ảo). Không có bộ khởi tạo (constructor) hoặc bộ hủy (destructor) đặc biệt. Cũng như Modula-3, không cócách viết tắt nào để tham chiếu tới các thành viên của một đối tượng từ các phương thức của nó: hàm phương thứcđược khai báo với thông số thứ nhất thể hiện chính đối tượng đó, và được tự động truyền vào qua lệnh gọi. Như trongSmalltalk, các class cũng là các đối tượng theo một nghĩa rộng: trong Python, mọi kiểu dữ liệu đều là các đối tượng.Điều này cho phép nhập (import) và đổi tên. Không như C++ và Modula-3, các kiểu có sẵn có thể được dùng nhưcác class cơ sở để mở rộng bởi người dùng. Và như trong C++ nhưng không giống Modula-3, đa số các toán tử cósẵn với cú pháp đặc biệt (các toán tử số học, truy cập mảng, v.v...) có thể được định nghĩa lại trong các trường hợpcụ thể của class.

Page 21: Học python

Chương III 19

về thuật ngữNhững từ chuyên ngành dùng ở đây theo từ vựng của Smalltalk và C++.Các đối tượng có tính cá thể (individuality), và nhiều tên (trong nhiều phạm vi, scope) có thể được gắn vào cùng mộtđối tượng. Trong các ngôn ngữ khác được gọi là tên lóng (alias). Nó thường không được nhận ra khi dùng Python lầnđầu, và có thể được bỏ qua khi làm việc với các kiểu bất biến cơ bản (số, chuỗi, bộ). Tuy nhiên, tên lóng có một ảnhhưởng đối với ý nghĩa của mã Python có sử dụng các đối tượng khả biến như danh sách, từ điển, và đa số các kiểuthể hiện các vật ngoài chương trình (tập tin, cửa sổ, v.v...). Nó thường được dùng vì tên lóng có tác dụng như là contrỏ theo một vài khía cạnh nào đó. Ví dụ, truyền một đối tượng vào một hàm rẻ vì chỉ có con trỏ là được truyền, vànếu một hàm thay đổi một đối tượng được truyền vào, thì nơi gọi sẽ thấy các thay đổi đó -- thay vì cần hai kiểutruyền thông số như trong Pascal.

Phạm vi trong Python và vùng tênTrước khi giới thiệu lớp, chúng ta sẽ cần hiểu phạm vi (scope) và vùng tên (namespace) hoạt động như thế nào vì cácđịnh nghĩa lớp sẽ sử dụng chúng. Kiến thức về vấn đề này cũng rất hữu dụng với những nhà lập trình Python chuyênnghiệp.Bắt đầu với một vài định nghĩa.• A namespace (vùng tên)là ánh xạ từ tên vào đối tượng. Đa số các vùng tên được cài đặt bằng từ điển Python,

nhưng điều đó thường là không quan trọng (trừ tốc độ), và có thể sẽ thay đổi trong tương lai. Các ví dụ vùng tênnhư: tập hợp các tên có sẵn (các hàm như abs(), và các tên biệt lệ có sẵn); các tên toàn cục trong một module; cáctên nội bộ trong một phép gọi hàm. Theo nghĩa đó tập hợp các thuộc tính của một đối tượng cũng là một vùng tên.Điều quan trọng cần biết về vùng tên là tuyệt đối không có quan hệ gì giữa các vùng tên khác nhau; ví dụ haimodule khác nhau có thể cùng định nghĩa hàm ``maximize mà không sợ lẫn lộn -- người dùng module phải thêmtiền tố tên module trước khi gọi hàm.

Cũng xin nói thêm là từ thuộc tính được dùng để chỉ mọi tên theo sau dấu chấm -- ví dụ, trong biểu thức z.real, reallà một thuộc tính của đối tượng z. Nói đúng ra, tham chiếu tới tên trong một module là các tham chiếu tới thuộc tính:trong biểu thức modname.funcname, modname là một đối tượng module và funcname là một thuộc tính của nó.Trong trường hợp này, việc ánh xạ giữa các thuộc tính của mô-đun và các tên toàn cục được định nghĩa trongmô-đun thật ra rất đơn giản: chúng dùng chung một vùng tên!

Ghi chú:vùng tên!

Trừ một chuyện. Các đối tượng mô-đun có một thuộc tính chỉ đọc gọi là

__dict__ trả về một từ điển dùng để cài đặt vùng tên của mô-đun; tên

__dict__ là một thuộc tính nhưng không phải là một tên toàn cục. Rõ

ràng, sử dụng nó vi phạm tính trừu tượng của cài đặt vùng tên, và nên

được giới hạn vào những chuyện như gỡ rối.

Thuộc tính có thể là chỉ đọc, hoặc đọc ghi. Trong trường hợp sau, phép gán vào thuộc tính có thể được thực hiện. Cácthuộc tính module là đọc ghi: bạn có thể viết "modname.the_answer = 42". Các thuộc tính đọc ghi cũng có thể đượcxóa đi với câu lệnh del . Ví dụ, "del modname.the_answer" sẽ xóa thuộc tính the_answer từ đối tượng tên modname.Các vùng tên được tạo ra vào những lúc khác nhau và có thời gian sống khác nhau. Vùng tên chứa các tên có sẵnđược tạo ra khi trình thông dịch Python bắt đầu, và không bao giờ bị xóa đi. Vùng tên toàn cục của một module đượctạo ra khi định nghĩa module được đọc; bình thường, vùng tên module cũng tồn tại cho tới khi trình thông dịch thoátra. Các câu lệnh được thực thi bởi lời gọi ở lớp cao nhất của trình thông dịch, vì đọc từ một kịch bản hoặc qua tươngtác, được coi như một phần của mdunle gọi là __main__, cho nên chúng cũng có vùng tên riêng. (Các tên có sẵn thậtra cũng tồn tại trong một module; được gọi là __builtin__.)

Page 22: Học python

Chương III 20

Vùng tên nội bộ của một hàm được tạo ra khi hàm được gọi, và được xóa đi khi hàm trả về, hoặc nâng một biệt lệkhông được xử lý trong hàm. Dĩ nhiên, các lời gọi hàm đệ quy có vùng tên riêng của chúng.• Phạm vi là một vùng văn bản của một chương trình Python mà một vùng tên có thể được truy cập trực tiếp. ``Có

thể truy cập trực tiếp có nghĩa là một tham chiếu không đầy đủ (unqualifed reference) tới một tên sẽ thử tìm tênđó trong vùng tên.

Mặc dù phạm vi được xác định tĩnh, chúng được dùng một cách động. Vào bất kỳ một lúc nào, có ít nhất ba phạm vilồng nhau mà vùng tên của chúng có thể được truy cập trực tiếp: phạm vi bên trong cùng, được tìm trước, chứa cáctên nội bộ; các vùng tên của các hàm chứa nó, được tìm bắt đầu từ phạm vi chứa nó gần nhất (nearest enclosingscope); phạm vi giữa (middle scope), được tìm kế, chứa các tên toàn cục của module; và phạm vi ngoài cùng (đượctìm sau cùng) là vùng tên chứa các tên có sẵn.Nếu một tên được khai báo là toàn cục, thì mọi tham chiếu hoặc phép gán sẽ đi thẳng vào phạm vi giữa chứa các têntoàn cục của module. Nếu không, mọi biến được tìm thấy ngoài phạm vi trong cùng chỉ có thể được đọc (nếu thử khivào các biến đó sẽ tạo một biến cục bộ mới trong phạm vi trong vùng, và không ảnh hưởng tới biến cùng tên ở phạmvi ngoài).Thông thường, phạm vi nội bộ tham chiếu các tên nội bộ của hàm hiện tại (dựa vào văn bản). Bên ngoài hàm, phạmvi nội bộ tham chiếu cùng một vùng tên như phạm vi toàn cục: vùng tên của module. Các định nghĩa lớp đặt thêmmột vùng tên khác trong phạm vi nội bộ.Điểm quan trọng cần ghi nhớ là phạm vi được xác định theo văn bản: phạm vi toàn cục của một hàm được địnhnghĩa trong một module là vùng tên của module đó, cho dù module đó được gọi từ đâu, hoặc được đặt tên lóng nào.Mặt khác, việc tìm tên được thực hiện lúc chạy -- tuy nhiên, định nghĩa ngôn ngữ đang phát triển theo hướng xácđịnh tên vào lúc ``dịch, cho nên đừng dựa vào việc tìm tên động! (Thực ra thì các biến nội bộ đã được xác địnhtĩnh.)

Một điểm ngộ của Python là các phép gán luôn gán vào phạm vi trong cùng. Phép gán không chép dữ liệu, chỉ buộccác tên và các đối tượng. Xóa cũng vậy: câu lệnh "del x" bỏ ràng buộc x khỏi vùng tên được tham chiếu tới bởi phạmvi nội bộ. Thực tế là mọi tác vụ có thêm các tên mới đều dùng phạm vi nội bộ: điển hình là các câu lệnh nhập và cácđịnh nghĩa hàm buộc tên module hoặc tên hàm vào phạm vi nội bộ. (Lệnh global có thể được dùng để cho biết mộtbiến cụ thể là ở phạm vi toàn cục.)

Cái nhìn đầu tiên về classclass thêm một ít cú pháp mới, ba kiểu đối tượng mới, và một ít ngữ nghĩa mới.

Cú pháp định nghĩa class

Kiểu đơn giản nhất của việc định nghĩa class nhìn giống như:

class ClassName:

<statement-1>

.

.

.

<statement-N>

Định nghĩa class, cũng như định nghĩa hàm (câu lệnh def ) phải được thực thi trước khi chúng có hiệu lực. (Bạn cóthể đặt một định nghĩa hàm trong một nhánh của lệnh if , hoặc trong một hàm.)Trong thực tế, các câu lệnh trong một định nghĩa class thường là định nghĩa hàm, nhưng các câu lệnh khác cũng đượccho phép, và đôi khi rất hữu dụng. Các định nghĩa hàm trong một class thường có một dạng danh sách thông số lạ, vìphải tuân theo cách gọi phương thức.

Page 23: Học python

Chương III 21

Khi gặp phải một định nghĩa class, một vùng tên mới được tạo ra, và được dùng như là phạm vi nội bộ. Do đó, mọiphép gán vào các biến nội bộ đi vào vùng tên này. Đặc biệt, các định nghĩa hàm buộc tên của hàm mới ở đây.Khi rời khỏi một định nghĩa class một cách bình thường, một đối tượng class được tạo ra. Đây cơ bản là một bộ gói(wrapper) của nội dung của vùng tên tạo ra bởi định nghĩa class. Phạm vi nội bộ ban đầu (trước khi vào định nghĩaclass) được thiết lập lại, và đối tượng class được buộc vào đây qua tên class đã chỉ định ở định nghĩa class,(ClassName trong ví dụ trên).

Đối tượng class

Các đối tượng class hỗ trợ hai loại tác vụ: tham chiếu thuộc tính và tạo trường hợp (instantiation).Tham chiếu thuộc tính dùng cú pháp chuẩn được dùng cho mọi tham chiếu thuộc tính trong Python: obj.name. Cáctên thuộc tính hợp lệ gồm mọi tên trong vùng tên của class khi đối tượng class được tạo ra. Do đó, nếu định nghĩaclass có dạng như sau:

class MyClass:

"A simple example class"

i = 12345

def f(self):

return 'hello'

thì MyClass.i và MyClass.f là những tham chiếu thuộc tính hợp lệ, trả về một số nguyên và một đối tượng hàm, theothứ tự đó. Các thuộc tính class cũng có thể gán vào, cho nên bạn có thể thay đổi giá trị của MyClass.i bằng phép gán.__doc__ cũng là một thuộc tính hợp lệ, trả về chuỗi tài liệu của class: "A simple example class".•• Class instantiation (tạo trường hợp lớp) dùng cùng cách viết như gọi hàm. Hãy tưởng tượng một đối tượng class là

một hàm không thông số trả về một trường hợp của class. Ví dụ (với class trên):

x = MyClass()

tạo một trường hợp mới của class và gán đối tượng này vào biến nội bộ x.• Tác vụ tạo trường hợp (``gọi một đối tượng class) tạo một đối tượng rỗng. Nhiều class thích tạo đối tượng với

các trường hợp được khởi tạo ở một trạng thái đầu nào đó. Do đó một class có thể định nghĩa một phươngthức đặc biệt tên __init__(), như sau:

def __init__(self):

self.data = []

Khi một class định nghĩa một phương thức __init__() , việc tạo trường hợp class sẽ tự động gọi __init__() ở trườnghợp class mới vừa được tạo. Trong ví dụ nạy, một trường hợp đã khởi tạo mới có thể được tạo ra từ:

x = MyClass()

Dĩ nhiên, __init__() (phương thức) có thể nhận thêm thông số. Trong trường hợp đó, các thông số đưa vào phép tạotrường hợp lớp sẽ được truyền vào __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)

Page 24: Học python

Chương III 22

Đối tượng trường hợp

Chúng ta có thể làm được gì với những đối tượng trường hợp? Tác vụ duy nhất mà các đối tượng trường hợp hiểuđược là tham chiếu thuộc tính. Có hai loại tên thuộc tính hợp lệ, thuộc tính dữ liệu và phương thức.• data attributes (thuộc tính dữ liệu lớp) tương ứng với ``biến trường hợp trong Smalltalk, và thành viên dữ liệu

trong C++. Thuộc tính dữ liệu không cần được khai báo; như các biến nội bộ, chúng tự động tồn tại khi đượcgán vào. Ví dụ, nếu x là một trường hợp của MyClass được tạo ra ở trên, đoạn mã sau in ra giá trị 16, màkhông chừa lại dấu vết:

x.counter = 1

while x.counter < 10:

x.counter = x.counter * 2

print x.counter

del x.counter

Loại tham chiếu thuộc tính trường hợp khác là một method (phương thức). Một phương thức là một hàm của một đốitượng. (Trong Python, từ phương thức không chỉ riêng cho trường hợp lớp: các kiểu đối tượng khác cũng có thể cóphương thức. Ví dụ, đối tượng danh sách có phương thức tên append, insert, remove, sort, v.v... Tuy nhiên, trongphần sau chúng ta sẽ chỉ dùng từ phương thức dể chỉ các phương thức của đối tượng trường hợp lớp, trừ khi được chỉđịnh khác đi.)Các tên phương thức hợp lệ của một đối tượng trường hợp phụ thuộc vào class của nó. Theo định nghĩa, mọi thuộctính của một class mà là những đối tượng hàm định nghĩa các phương thức tương ứng của các trường hợp của classđó. Trong ví dụ của chúng ta, x.f là một tham chiếu phương thức hợp lệ, vì MyClass.f là một hàm, nhưng x.i khôngphải, bởi vì MyClass.i không phải. Nhưng x.f không phải là một thứ như MyClass.f nó là một method object (đốitượng phương thức), không phải là một đối tượng hàm.

Đối tượng phương thức

Thông thường, một phương thức được gọi ngay sau khi nó bị buộc:

x.f()

Trong MyClass , nó sẽ trả về chuỗi 'hello'. Tuy nhiên, cũng không nhất thiết phải gọi một phương thức ngay lập tức:x.f là một đối tượng phương thức, và có thể được cất đi và gọi vào một thời điểm khác. Ví dụ:

xf = x.f

while True:

print xf()

sẽ tiếp tục in "hello" mãi mãi.Chuyện gì thật sự xảy ra khi một phương thức được gọi? Bạn có thể đã nhận ra rằng x.f() được gọi với không thôngsố, mặc dù định nghĩa hàm của f chỉ định một thông số. Chuyện gì xảy ra với thông số đó? Python chắc chắn nângmột biệt lệ khi một hàm cần một thông số được gọi suông cho dù thông số đó có được dùng hay không đi nữa...Thật ra, bạn cũng có thể đã đoán ra được câu trả lời: điểm đặc biệt của phương thức là đối tượng đó được truyền vàoở thông số đầu tiên của hàm. Trong ví dụ của chúng ta, lời gọi x.f() hoàn toàn tương đương với MyClass.f(x). Nóichung, gọi một hàm với một danh sách n thông số thì tương đương với việc gọi hàm tương ứng với một danh sáchthông số được tạo ra bằng cách chèn đối tượng của phương thức vào trước thông số thứ nhất.(Hiểu đơn giản là obj.name(arg1, arg2) tương đương với Class.name(obj, arg1, arg2) trong đó obj là đối tượngtrường hợp của lớp Class, name là một thuộc tính hợp lệ không phải dữ liệu, tức là đối tượng hàm của lớp đó.)

Page 25: Học python

Chương III 23

Một vài lời bìnhThuộc tính dữ liệu sẽ che thuộc tính phương thức cùng tên; để tránh vô tình trùng lặp tên, mà có thể dẫn đến các lỗirất khó tìm ra trong các chương trình lớn, bạn nên có một quy định đặt tên nào đó để giảm thiểu tỉ lệ trùng lặp. Cácquy định khả thi có thể gồm viết hoa tên phương thức, đặt tiền tố vào các tên thuộc tính dữ liệu (ví dụ như dấu gạchdưới _), hoặc dùng động từ cho phương thức và danh từ cho các thuộc tính dữ liệu.Các thuộc tính dữ liệu có thể được tham chiếu tới bởi cả phương thức lẫn người dùng đối tượng đó. Nói một cáchkhác, lớp không thể được dùng để cài đặt các kiểu dữ liệu trừu tượng tuyệt đối. Trong thực tế, không có gì trongPython có thể ép việc che dấu dữ liệu, tất cả đều dựa trên nguyên tắc. (Mặt khác, cài đặt Python, được viết bằng C,có thể dấu các chi tiết cài đặt và điểu khiển truy cập vào một đối tượng nếu cần; điều này có thể được dùng trong cácbộ mở rộng Python viết bằng C.)Người dùng nên dùng các thuộc tính dữ liệu một cách cẩn thận, người dùng có thể phá hỏng những bất biến(invariant) được giữ bởi các phương thức nếu cố ý sửa các thuộc tính dữ liệu. Lưu ý rằng người dùng có thể thêm cácthuộc tính dữ liệu riêng của họ vào đối tượng trường hợp mà không làm ảnh hưởng tính hợp lệ của các phương thức,miễn là không có trùng lặp tên, xin nhắc lại, một quy tắc đặt tên có thể giảm bớt sự đau đầu ở đây.Không có cách ngắn gọn để tham chiếu tới thuộc tính dữ liệu (hoặc các phương thức khác!) từ trong phương thức.Điều này thật ra giúp chúng ta dễ đọc mã vì không có sự lẫn lộn giữa biến nội bộ và biến trường hợp.Thông số đầu tiên của phương thức thường được gọi là self. Đây cũng chỉ là một quy ước: tên self hoàn toàn khôngcó ý nghĩa đặc biệt trong Python. (Tuy nhiên xin nhớ nếu bạn không theo quy ước thì mã của bạn sẽ có thể trở nênkhó đọc đối với người khác, và có thể là trình duyệt class được viết dựa trên những quy ước như vậy.)Bất kỳ đối tượng hàm nào mà là thuộc tính của một class sẽ định nghĩa một phương thức cho các trường hợp củaclass đó. Không nhất thiết định nghĩa hàm phải nằm trong định nghĩa class trên văn bản: gán một đối tượng hàm vàomột biến nội bộ trong class cũng được. Ví dụ:

# Function defined outside the class

def f1(self, x, y):

return min(x, x+y)

class C:

f = f1

def g(self):

return 'hello'

h = g

Bây giờ f, g và h đều là thuộc tính của lớp C mà tham chiếu tới các đối tượng hàm, và do đó chúng đều là phươngthức của các trường hợp của C -- h hoàn toàn tương đương với g. Chú ý rằng kiểu viết này thường chỉ làm người đọccàng thêm khó hiểu mà thôi.Phương thức có thể gọi phương thức khác thông qua thuộc tính phương thức của thông số self :

class Bag:

def __init__(self):

self.data = []

def add(self, x):

self.data.append(x)

def addtwice(self, x):

self.add(x)

self.add(x)

Phương thức có thể tham chiếu tới các tên toàn cục theo cùng một cách như các hàm thông thường. Phạm vi toàn cụccủa một phương thức là module chứa định nghĩa class. (Phạm vi toàn cục không bao giờ là class) Trong khi bạn ít

Page 26: Học python

Chương III 24

gặp việc sử dụng dữ liệu toàn cục trong một phương thức, có những cách dùng hoàn toàn chính đáng: ví dụ như hàmvà module được nhập vào phạm vi toàn cục có thể được sử dụng bởi phương thức, cũng như hàm và class được địnhnghĩa trong đó. Thông thường, class chứa các phương thức này được định nghĩa ngay trong phạm vi toàn cục, vàtrong phần kế đây chúng ta sẽ thấy tại sao một phương thức muốn tham chiếu tới chính class của nó.

Kế thừaDĩ nhiên, một tính năng ngôn ngữ sẽ không đáng được gọi là class nếu nó không hỗ trợ kế thừa. Cú pháp của mộtđịnh nghĩa lớp con như sau:

class DerivedClassName(BaseClassName):

<statement-1>

.

.

.

<statement-N>

Tên BaseClassName phải đã được định nghĩa trong một phạm vi chứa định nghĩa lớp con. Thay vì tên lớp cơ sở, cácbiểu thức khác cũng được cho phép. Điều này rất hữu ích, ví dụ, khi mà lớp cơ sở được định nghĩa trong một modulekhác:

class DerivedClassName(modname.BaseClassName):

Việc thực thi định nghĩa class con tiến hành như là class cơ sở. Khi một đối tượng class được tạo ra, class cơ sở sẽđược nhớ. Nó được dùng trong việc giải các tham chiếu thuộc tính: nếu một thuộc tính không được tìm thấy ở trongclass, việc tìm kiếm sẽ tiếp tục ở class cơ sở. Luật này sẽ được lặp lại nếu class cơ sở kế thừa từ một class khác.Không có gì đặc biệt trong việc tạo trường hợp của các class con: DerivedClassName() tạo một trường hợp của class.Các tham chiếu hàm được giải như sau: thuộc tính lớp tương ứng sẽ được tìm, đi xuống chuỗi các class cơ sở nếucần, và tham chiếu phương thức là hợp lệ nếu tìm thấy một đối tượng hàm.class con có thể định nghĩa lại các phương thức của class cơ sở. Bởi vì phương thức không có quyền gì đặc biệt khigọi một phương thức của cùng một đối tượng, một phương thức của class cơ sở gọi một phương thức khác được địnhnghĩa trong cùng class cơ sở có thể là đang gọi một phương thức do class con đã định nghĩa lại. (Người dùng C++ cóthể hiểu là mọi phương thức của Python là virtual.)Một phương thức được định nghĩa lại trong class con có thể muốn mở rộng thay vì thay thế phương thức cùng têncủa class cơ sở. Có một cách đơn giản để gọi phương thức của class sơ sở: chỉ việc gọi"BaseClassName.methodname(self, arguments)". Đôi khi điều này cũng có ích cho người dùng. (Lưu ý rằng đoạn mãchỉ hoạt động nếu class cơ sở được định nghĩa hoặc nhập trực tiếp vào phạm vi toàn cục.)

Đa kế thừa

Python cũng hỗ trợ một dạng đa kế thừa hạn chế. Một định nghĩa class với nhiều lớp cơ sở có dạng sau:

class DerivedClassName(Base1, Base2, Base3):

<statement-1>

.

.

.

<statement-N>

Luật duy nhất cần để giải thích ý nghĩa là luật giải các tham chiếu thuộc tính của class. Nó tuân theo luật tìm theochiều sâu, và tìm trái qua phải. Do đó, nếu một thuộc tính không được tìm ra trong DerivedClassName, nó sẽ được

Page 27: Học python

Chương III 25

tìm trong Base1, rồi (đệ quy) trong các lớp cơ sở của Base1, rồi chỉ khi nó không được tìm thấy, nó sẽ được tìm trongBase2, và cứ như vậy.(Đối với một số người tìm theo chiều rộng -- tìm Base2 và Base3 trước các lớp cơ sở của Base1 -- có vẻ tự nhiênhơn. Nhưng, điều này yêu cầu bạn biết một thuộc tính nào đó của Base1 được thật sự định nghĩa trong Base1 haytrong một trong các lớp cơ sở của nó trước khi bạn có thể biết được hậu quả của sự trùng lặp tên với một thuộc tínhcủa Base2. Luật tìm theo chiều sâu không phân biệt giữa thuộc tính trực tiếp hay kế thừa của Base1.)Ai cũng biết rằng việc dùng đa kế thừa bừa bãi là một cơn ác mộng cho bảo trì, đặc biệt là Python dựa vào quy ướcđể tránh trùng lặp tên. Một vấn đề cơ bản với đa kế thừa là một lớp con của hai lớp mà có cùng một lớp cơ sở. Mặcdù dễ hiểu chuyện gì xảy ra trong vấn đề này (trường hợp sẽ có một bản chép duy nhất của ``các biến trường hợpcủa các thuộc tính dữ liệu dùng bởi lớp cơ sở chung), nó không rõ cho lắm nếu các ý nghĩa này thật sự hữu ích.

Biến riêngCó một dạng hỗ trợ nho nhỏ nho các từ định danh riêng của lớp (class-private identifier). Các từ định danh có dạng__spam (ít nhất hai dấu gạch dưới ở đầu, nhiều nhất một dấu dạch dưới ở cuối) được thay thế văn bản (textuallyreplace) bằng _classname__spam, trong đó classname là tên lớp hiện tại với các gạch dưới ở đầu cắt bỏ. Việc xáotrộn tên (mangling) được thực hiện mà không quan tâm tới vị trí cú pháp của định danh, cho nên nó có thể được dùngđể định nghĩa các trường hợp, biến, phương thức, riêng của lớp, hoặc các biến toàn cục, và ngay cả các biến củatrường hợp, riêng với lớp này trên những trường hợp của lớp khác . Nếu tên bị xáo trộn dài hơn 255 ký tự thì nó sẽ bịcắt đi. Bên ngoài lớp, hoặc khi tên lớp chỉ có ký tự gạch dưới, việc xáo trộn tên sẽ không xảy ra.Xáo trộn tên nhằm cung cấp cho các lớp một cách định nghĩa dễ dàng các biến và phương thức ``riêng, mà khôngphải lo về các biến trường hợp được định nghĩa bởi lớp con, hoặc việc sử dụng biến trường hợp bởi mã bên ngoàilớp. Lưu ý rằng việc xáo trộn tên được thiết kế chủ yếu để tránh trùng lặp; người quyết tâm vẫn có thể truy cậphoặc thay đổi biến riêng. Và điều này cũng có thể có ích trong các trường hợp đặc biệt, như trong trình gỡ rối, vàđó là một lý do tại sao lỗ hổng này vẫn chưa được vá.

Lưu ý rằng mã truyền vào exec, eval() hoặc execfile() không nhận tên lớp của lớp gọi là tên lớp hiện tại; điều nàycũng giống như tác dụng của câu lệnh global , tác dụng của nó cũng bị giới hạn ở mã được biên dịch cùng. Cùng giớihạn này cũng được áp dụng vào getattr(), setattr() và delattr(), khi tham chiếu __dict__ trực tiếp.

Những điều khácĐôi khi nó thật là hữu ích khi có một kiểu dữ liệu giống như Pascal ``record hoặc C ``struct, gói gọn vài mẩu dữ liệuvào chung với nhau. Một định nghĩa lớp rỗng thực hiện được việc này:

class Employee:

pass

john= Employee() # Create an empty employee record

# Fill the fields of the record

john.name = 'John Doe'

john.dept = 'computer lab'

john.salary = 1000

Với mã Python cần một kiểu dữ liệu trừu tượng, ta có thể thay vào đó một lớp giả lập các phương thức của kiểu dữliệu đó. Ví dụ, nếu bạn có một hàm định dạng một vài dữ liệu trong một đối tượng tập tin, bạn có thể định nghĩa mộtlớp với các phương thức read() và readline() lấy dữ liệu từ một chuỗi, và truyền vào nó một thông số.Các đối tượng phương trức trường hợp cũng có thuộc tính: m.im_self là một đối tượng trường hợp với phương thứcm, và m.im_func là đối tượng hàm tương ứng với phương thức.

Page 28: Học python

Chương III 26

Biệt lệ cũng là lớpCác biệt lệ được định nghĩa bởi người dùng cũng được định danh theo lớp. Bằng cách này, một hệ thống phân cấpbiệt lệ có thể được tạo ra. Có hai dạng lệnh raise mới: raise Class, instanceraise instance Trong dạng đầu, instance phải là một trường hợp của kiểu Class hoặc là lớp con của nó. Dạng thứ hailà rút gọn của: raise instance.__class__, instance Lớp trong vế except tương thích với một biệt lệ nếu nó cùng lớp,hoặc là một lớp cơ sở (nhưng chiều ngược lại thì không đúng -- một vế except dùng lớp con sẽ không tương thích vớimột biệt lệ lớp cơ sở). Ví dụ, đoạn mã sau sẽ in B, C, D theo thứ tự đó:

class B:

pass

class C(B):

pass

class D(C):

pass

for c in [B, C, D]:

try:

raise c()

except D:

print "D"

except C:

print "C"

except B:

print "B"

Nếu các vế except được đặt ngược (với "except B" ở đầu), nó sẽ in B, B, B -- vế except phù hợp đầu tiên được thựcthi. Khi một thông điệp lỗi được in, tên lớp của biệt lệ được in, theo sau bởi dấu hai chấm và một khoảng trắng, vàcuối cùng là trường hợp đã được chuyển thành chuỗi bằng hàm có sẵn str().

Bộ lặpBây giờ có lẽ bạn đã lưu ý rằng hầu hết các đối tượng chứa (container object) có thể được lặp qua bằng câu lệnh for :

for element in [1, 2, 3]:

print element

for element in (1, 2, 3):

print element

for key in {'one':1, 'two':2}:

print key

for char in "123":

print char

for line in open("myfile.txt"):

print line

Kiểu truy xuất này rõ ràng, xúc tích, và tiện lợi. Bộ lặp (iterator) được dùng khắp nơi và hợp nhất Python. Đằng saumàn nhung, câu lệnh for gọi iter() trên đối tượng chứa. Hàm này trả về một đối tượng bộ lặp có định nghĩa phươngthức next() để truy xuất và các phần tử trong bộ chứa (container). Khi không còn phần tử nào, next() nâng biệt lệStopIteration để yêu cầu vòng lặp for kết thúc. Ví dụ sau cho thấy cách hoạt động:

Page 29: Học python

Chương III 27

>>> s = 'abc'

>>> it = iter(s)

>>> it

<iterator object at 0x00A1DB50>

>>> it.next()

'a'

>>> it.next()

'b'

>>> it.next()

'c'

>>> it.next()

Traceback (most recent call last):

File "<stdin>", line 1, in ?

it.next()

StopIteration

Chúng ta đã hiểu giao thức bộ lặp, nên chúng ta có thể thêm cách thức bộ lặp (iterator behavior) vào lớp của chúng tamột cách dễ dàng. Định nghĩa một phương thức __iter__() trả về một đối tượng với một phương thức next() . Nếulớp có định nghĩa next(), thì __iter__() chỉ cần trả về self:

class Reverse:

"Iterator for looping over a sequence backwards"

def __init__(self, data):

self.data = data

self.index = len(data)

def __iter__(self):

return self

def next(self):

if self.index == 0:

raise StopIteration

self.index = self.index - 1

return self.data[self.index]

>>> for char in Reverse('spam'):

... print char

...

m

a

p

s

Page 30: Học python

Chương III 28

Bộ tạo

Bộ sinh (generator) là một công cụ đơn giản và mạnh mẽ để tạo các bộ lặp. Chúng được viết như những hàm thôngthường nhưng dùng câu lệnh yield khi nào chúng muốn trả về dữ liệu. Mỗi lần next() được gọi, bộ sinh trở lại nơi nóđã thoát ra (nó nhớ mọi dữ liệu và câu lệnh đã được thực thi lần cuối). Một ví dụ cho thấy bộ sinh có thể được tạo rarất dễ dàng:

def reverse(data):

for index in range(len(data)-1, -1, -1):

yield data[index]

>>> for char in reverse('golf'):

... print char

...

f

l

o

g

Bất kỳ việc gì có thể được thực hiện với bộ sinh cũng có thể được thực hiện với các bộ lặp dựa trên lớp như đã bànđến ở phần trước. Điều khiến bộ sinh nhỏ gọn là các phương thức __iter__() và next() được tự động tạo ra. Một tínhnăng chính khác là các biến nội bộ và trạng thái thực thi được tự động lưu giữa các lần gọi. Điều này làm cho hàm dễviết hơn và rõ ràng hơn là cách sử dụng biến trường hợp như self.index và self.data. Thêm vào việc tự động tạo vàlưu trạng thái chương trình, khi các bộ tạo kết thúc, chúng tự động nâng StopIteration. Cộng lại, các tính năng nàylàm cho việc tạo các bộ lặp không có gì khó hơn là viết một hàm bình thường.

Biểu thức bộ tạoMột vài bộ sinh đơn giản có thể được viết một cách xúc tích như các biểu thức bằng cách dùng một cú pháp giốngnhư gộp danh sách (list comprehension) nhưng với ngoặc tròn thay vì ngoặc vuông. Các biểu thức này được thiết kếcho những khi bộ sinh được sử dụng ngay lập tức bởi hàm chứa nó. Biểu thức bộ sinh gọn hơn nhưng ít khả chuyểnhơn là các định nghĩa bộ sinh đầy đủ và thường chiếm ít bộ nhớ hơn là gộp danh sách tương đương. Ví dụ:

>>> sum(i*i for i in range(10)) # sum of squares

285

>>> xvec = [10, 20, 30]

>>> yvec = [7, 5, 3]

>>> sum(x*y for x,y in zip(xvec, yvec)) # dot product

260

>>> from math import pi, sin

>>> sine_table = dict((x, sin(x*pi/180)) for x in range(0, 91))

>>> unique_words = set(word for line in page for word in line.split())

>>> valedictorian = max((student.gpa, student.name) for student in graduates)

>>> data = 'golf'

>>> list(data[i] for i in range(len(data)-1,-1,-1))

['f', 'l', 'o', 'g']

Page 31: Học python

Chương IV 29

Chương IVChương này sẽ nói về sức mạnh của Python . Như bạn đã biết , mọi thứ trong python là một đối tượng , code được tracứa trong các modules và phương thức trong bộ nhớ như một đối tượng , lấy thông tin về chúng, và thao tác trênchúng .

Diving InVí dụ : apihelper.py ( (http:/ / diveintopython. org/ download/ diveintopython−examples−5. 4. zip )

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

""" Print methods and doc string .

Takes module , class , list , dictionary , or string ."""

methodList = [method for method in dir(object) if callable(getattr(object, method))]

processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)

print "\n".join(["%s %s" %

(method.ljust(spacing),

processFunc(str(getattr(object, method).__doc__)))

for method in methodList])

if __name__ == "__main__":

print info.__doc__

•• Module này có 1 hàm , info . Trong khai báo hàm , có ba tham số : object , spacing , and collapse . Có 2 tham sốđược chọn lựa .

•• Hàm info có nhiều dòng doc mô tả ngắn gọn mục đích của hàm . Chú ý rằng không có giá trị trả về được đề cập .•• Code trong hàm thì được thụt vào .•• if __name__ lừa gạt , cho phép chương trình làm một cái gì đó hữa dụng hơn khi chạy bởi chính nó mà không

quan tâm đến chương trình sử dụng module của chương trình khác . Trong trường hợp này , chương trình đơngiản chỉ in ra chuổi doc của hàm info .

•• Hàm info được thiết kế để được sử dụng bởi bạn , người lập trình , trong khi làm việc với Python IDE. Chươngtrình lấy bất kì đối tượng có hàm hay phương thức và in ra ngoài .

Ví dụ :

>>> from apihelper import info

>>> li = []

>>> info(li)

append L.append(object) −− append object to end

count L.count(value) −> integer −− return number of occurrences of value extend L.extend(list) −− extend list by appending list elements index L.index(value) −> integer −− return index of first occurrence of value insert L.insert(index, object) −− insert object before index pop L.pop([index]) −> item −− remove and return item at index (default last) remove L.remove(value) −− remove first occurrence of value reverse L.reverse() −− reverse *IN PLACE* sort L.sort([cmpfunc]) −− sort *IN PLACE*; if given, cmpfunc(x, y) −> −1, 0, 1

Page 32: Học python

Chương IV 30

Mặc định output được định dạng để có thể dể dàng đọc . Chuổi Multi-line doc thì chuyển thành một hàng đơn ,nhưng lựa chọn này có thể được thay đổi bởi đặc tả số 0 cho tham số collapse . Nếu những tên hàm dài hơn 10 kí tự .Bạn có thể đặc tả giá trị lớn hơn bởi tham số spacing để làm output dể đọc hơnVí dụ :

>>> import odbchelper

>>> info(odbchelper)

buildConnectionString Build a connection string from a dictionary Returns string.

>>> info(odbchelper, 30)

buildConnectionString Build a connection string from a dictionary Returns string.

>>> info(odbchelper, 30, 0)

buildConnectionString Build a connection string from a dictionary

Returns string.

Using Optional and Named ArgumentsPython cho phép tham số hàm có giá trị mặc định . Nếu hàm được gọi mà không có tham số , tham số sẽ lấy giá trịmặc định . Xa hơn , tham số có thể được đặc tả trong bất cứ thứ bật với việc sử dụng tên tham số . Thủ tục lưu trửtrong SQL Server transact/SQL có thể làm điều này .Đây là một ví dụ về info , một hàm với hai tham số chọn :

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

Example Những cách gọi info hợp lệ

info(odbchelper)

info(odbchelper , 12 )

info(odbchelper, collapse=0)

info(spacing=15, object=odbchelper)

•• Với duy nhất một tham số , spacing và collapse lấy giá trị mặc định là 10 và 1 .•• Với 2 tham số , collapse lấy giá trị mặc định .•• Do đặt tên collapse = 0 , nên collapse sẽ có tra trị là 0 , bất chấp thứ tự . còn spacing có giá trị là mặc định .•• Ngay cả tham số được đòi hỏi ( giống object ) có thể được đặt tên , và tham số được đặt tên có thể xuất hiện ở bất

cứ đâu .

Using type , str , dir , and Other Built - In FunctionsPython có một tập hợp nhỏ extremely các hàm hữu dụng . Tất cả hàm được tách ra vào trong các modules . Điều nàylà một quyết định thiết kế tỉnh táo , để giữ core language trở nên phồng lên giống bất cứ ngôn ngữ kịch bản khác (cough cough , Visual basic ) .

The type functionHàm type trả về kiểu giá trị của bất kì đối tượng tùy thích nào . Các lọai khả thi , thì được liệt kê trong types module.Vídụ : Introducing type

>>> type(1)

<type 'int'>

>>> li = []

>>> type(li)

Page 33: Học python

Chương IV 31

<type 'list'>

>>> import odbchelper

>>> type(odbchelper)

<type 'module'>

>>> import types

>>> type(odbchelper) == types.ModuleType

True

•• type lấy bất cứ thứ gì , và trả về kiểu dữ liệu của nó . Integers , strings , lists , dictionaries ,...•• type lấy một giá trị variable và trả về kiểu dữ liệu của nó .•• type cũng có thể làm việc trong những modules .•• bạn có thể sử dụng hằng trong module types để so sánh lọai đối tượng .

The str FunctionVí dụ : Introducing str

>>> str(1)

'1'

>>> horsemen = ['war', 'pestilence', 'famine']

>>> horsemen

['war', 'pestilence', 'famine']

>>> horsemen.append('Powerbuilder')

>>> str(horsemen)

"['war', 'pestilence', 'famine', 'Powerbuilder']"

>>> str(odbchelper)

"<module 'odbchelper' from 'c:\\docbook\\dip\\py\\odbchelper.py'>"

>>> str(None)

'None'

•• Trong kiểu dử liệu đơn giản giống số nguyên . Bạn sẽ mong chờ str làm việc , bởi vì hầu như mỗi ngôn ngữ cómột hàm để chuyển số nguỵên thành một chuỗi .

•• Dù sao đi nữa , str làm việc trên bất kì đối tượng của bất cứ lọai nào . Ở đây nó làm việc trên danh sách .•• str cũng làm việc trên modules . Chú ý rằng sự biểu diễn chuỗi của module bao gồm pathname của module trên

disk .Ví dụ : Introducing dir

>>> li = []

>>> dir(li)

['append', 'count', 'extend', 'index', 'insert',

'pop', 'remove', 'reverse', 'sort']

>>> d = {}

>>> dir(d)

['clear', 'copy', 'get', 'has_key', 'items', 'keys', 'setdefault', 'update', 'values']

>>> import odbchelper

>>> dir(odbchelper)

['__builtins__', '__doc__', '__file__', '__name__', 'buildConnectionString']

•• li là một danh sách , vì vật dir(li) trả về một danh sách của tất cả các phương thực của danh sách. Chú ý rằng danhsách được trả về chứa tên cửa phương thức như là chuỗi , không phải là phương thức của chúng .

Page 34: Học python

Chương IV 32

•• d là một thư mục, vì vậy dir(d) trả về một danh sách của tên các phương thức thư mục .•• Điều này thật sự kích thích . odbchelper là một module , vì vậy dir(odbchelper) trả về một danh sách của tất cả

các định nghĩa trong module .Ví dụ : Introducing callable

>>> import string

>>> string.punctuation

'!"#$%&\'()*+,−./:;<=>?@[\\]^_`{|}~' >>> string.join

<function join at 00C55A7C>

>>> callable(string.punctuation)

False

>>> callable(string.join)

True

>>> print string.join.__doc__

join(list [,sep]) −> string Return a string composed of the words in list, with

intervening occurrences of sep. The default separator is a

single space.

•• Những hàm trong module string thì phản kháng ( mặc dù nhiều người vẫn còn dùng hàm join ). Nhưng modulechứa nhiều hằng có ích giống như string.punctuation , chứa tất cả kí tự chấm câu tiêu chuẩn .

•• string.join là hàm dùng để join một danh sách các chuỗi .•• string.punctuation thì không thể được gọi ; nó là một chuỗi ( Một String có phương thức callable ,nhưng chuỗi của

chính nó thì không có ) .•• string.join is callable , nó là một hàm lấy hai tham số .•• Bất cứ đối tượng callables có thể có một doc string . Sử dụng hàm callable trên mỗi một thuộc tính của đối tượng ,

bạn có thể xác định , thuộc tính bạn quan tâm , và cái nào mà bạn muốn bỏ qua .

Built-In Functiontype, str, dir, and all the rest of Python's built−in functions được nhóm thành một modules đặc biệt được gọi là__builtin__. Bạn có thể nghĩ rằng python tự động thực thi " from __builtin__ import * " on startup . Ưu điểm củađiều này là bạn có thể truy câp tất cả hàm built-in và thuộc tính như một nhóm bởi lấy thông tin về __builtin__module .Ví dụ : Built−in Attributes and Functions

>>> from apihelper import info

>>> import __builtin__

>>> info(__builtin__, 20)

ArithmeticError Base class for arithmetic errors.

AssertionError Assertion failed.

AttributeError Attribute not found

EOFError Read beyond end of file.

EnvironmentError Base class for I/O related errors.

Exception Common base class for all exceptions.

FloatingPointError Floating point operation failed.

IOError I/O operation failed.

Page 35: Học python

Chương IV 33

Getting Object References with getattrBạn đã biết về hàm và đối tượng trong python . Bạn khôn biết điều gì có thể tham chiếu tới một hàm mà không cầnbiết nó đang chạy , bằng sử dụng getattr function .Ví dụ Introducing getattr

>>> li = ["Larry", "Curly"]

>>> li.pop

<built−in method pop of list object at 010DF884> >>> getattr(li, "pop")

<built−in method pop of list object at 010DF884> >>> getattr(li, "append")("Moe")

>>> li

["Larry", "Curly", "Moe"]

>>> getattr({}, "clear")

<built−in method clear of dictionary object at 00F113D4> >>> getattr((), "pop")

Traceback (innermost last):

File "<interactive input>", line 1, in ?

AttributeError: 'tuple' object has no attribute 'pop'

•• Điều này lấy một tham chiếu tới phương thức pop trên danh sách . Chú ý rằng điều này không gọi phương thứcpop . Nếu vậy sẽ là li.pop() . Đây là phương thức của chính nó .

• Điều này cũng trả về một tham chiếu tới phương thức pop , tên phương thức được miêu tả như là một chuỗi , thamsố tới hàm getattr . getattr là một hàm built−in hữu dụng không thể ngờ cái trả về bất cứ thuộc tính của bất cứ đốitượng . Trong trường hợp này , đối tượng là một danh sách , và thuộc tính là phương thức pop .

•• Giá trị trả về của getattr là một phương thức .•• getattr cũng làm việc trên từ điển .•• Trong lý thuyết , getattr sẽ làm việc trên tuples , trừ ra tuples không có phương thức , vì vậy getattr sẽ ném một

ngọai lệ , không vấn đề gì về tên thuộc tính mà bạn đưa .

getattr with ModulesVí dụ . The getattr Function in apihelper.py

>>> import odbchelper

>>> odbchelper.buildConnectionString

<function buildConnectionString at 00D18DD4>

>>> getattr(odbchelper, "buildConnectionString")

<function buildConnectionString at 00D18DD4>

>>> object = odbchelper

>>> method = "buildConnectionString"

>>> getattr(object, method)

<function buildConnectionString at 00D18DD4>

>>> type(getattr(object, method))

<type 'function'>

>>> import types

>>> type(getattr(object, method)) == types.FunctionType

True

Page 36: Học python

Chương IV 34

>>> callable(getattr(object, method))

True

•• Điều này trả về một tham chiếu tới hàm buildConnectionString trong module odbchelper•• Sử dụng getattr, bạn có thể tham chiếu tới hàm . getattr(object,"attribute") thì tương ứng với object.attribute. Nếu

đối tượng có một module , thì thuộc tính có thể được đinh nghĩa bất kỳ trong module : a function, class, or globalvariable.

•• Và điều này là cái gì bạn thật sự dùng trong hàm info. Đối tượng được truyền vào trong hàm như tham số .Phương thức là một chuổi , thì cùng tên với phương thức hay hàm .

method is a string which is the name of a method or function.•• Trong trường hợp này , phương thức là tên của một hàm.

getattr As a DispatcherVí dụ : Creating a Dispatcher with getattr

import statsout

def output(data, format="text"):

output_function = getattr(statsout, "output_%s" % format)

return output_function(data)

•• Hàm output đòi hỏi một tham số ( data ) , và một tham số chon lựa ( format ). Nếu format thì không được truyền ,nó sẽ mặc định là text .

•• Giá trị là một tham chiếu to hàm thích hợp từ module statsout.Ví dụ : getattr Default Values

import statsout

def output(data, format="text"):

output_function = getattr(statsout, "output_%s" % format, statsout.output_text)

return output_function(data)

•• Gọi Hàm này is đảm bảo để làm việc , bởi vì bạn thêm ba tham số để gọi getattr .•• Tham số thứ ba là một giá trị mặc định và được trả về . Nếu thuộc tính hay phương thức đặc tả bởi tham số thứ

hai thì không tìm thấy .

Filtering ListPython có khả năng ánh xạ danh sách vào trong danh sách khác .Đây là cú pháp lọc danh sách : [mapping−expression for element in source−list if filter−expression]Ví dụ : Introducing List Filtering

>>> li = ["a", "mpilgrim", "foo", "b", "c", "b", "d", "d"]

>>> [elem for elem in li if len(elem) > 1]

['mpilgrim', 'foo']

>>> [elem for elem in li if elem != "b"]

['a', 'mpilgrim', 'foo', 'c', 'd', 'd']

>>> [elem for elem in li if li.count(elem) == 1]

['a', 'mpilgrim', 'foo', 'c']

•• Biểu thức ánh xạ ở đây thì đơn giản ( nó chỉ trả về giá trị của mỗi phần tử ), vì vậy nên tập trung vào biểu thức lọc( filter ). Trong khi vòng lặp Python thông quan danh sách , nó chạy qua mỗi phần tử trong mảng và đưa vào biểu

Page 37: Học python

Chương IV 35

thức lọc. Nếu biểu thức lọc là true , phần tử được ánh xạ và kết quả của biểu thức ánh xạ là danh sách .

The Peculiar Nature of and and orTrong Python , and va or and được biểu diển boolean luận lí , nhưng chúng không trả về giá trị boolean . Thực tế ,chúng trả về một trong những giá trị thực mà chúng đang so sánh .Ví dụ : Introducing and

>>> 'a' and 'b'

'b'

>>> and 'b'

>>> 'a' and 'b' and 'c'

'c'

• Khi dùng and , giá trị được ước lượng trong một ngữ cảnh luận lí ( in a boolean context ) từ trái sang phải . 0, , [],(), {}, và None là false trong ngử cảnh boolean ; mỗi thứ khác đều là true . Mặc định , ví dụ classes là true trongboolean context , nhưng bạn không thể định nghĩa phương thức đặc tả trong lớp của anh để làm ví dụ cho false

• Nếu bất kỳ giá trị là false trong boolean context , và trả về giá trị đầu tiên là false . Trong trường hợp này , là giátrị false đầu tiên .

•• Tất cả giá trị là true , vì vậy trả về giá trị cuối là , 'c'.Ví dụ : Introducing or

>>> 'a' or 'b'

'a'

>>> or 'b'

'b'

>>> or [] or {}

{}

>>> def sidefx():

... print "in sidefx()"

... return 1

>>> 'a' or sidefx()

'a'

•• Khi dùng or , giá trị thì ước lượng trong boolean context từ trái sang phải . Nếu bất cứ giá trị là true hoặc trả vềgiá tri đó lập tức . Trong trường hợp này , 'a' là giá trị true đầu tiên .

• Ta có là false, rồi 'b' là true, và trả về 'b'.• Nếu tất cả giá trị là false hoặc trả về giá trị cuối . Ta có là false , rồi [] là false, rồi {} cũng là false , sẽ trả về giá

trị {} .•• Chú ý rằng or ước lương các giá trị đến khi or tìm thấy một cái là true trong boolean context, và sau đó nó bỏ quả

và nghĩ . Điều này quan trong nếu vài giá trị có thể có hiệu ứng bên cạnh . sidefx hàm thì không bao giờ được gọi, bởi vì ước lượng 'a' is true, và trả về 'a'lập tức.

Page 38: Học python

Chương IV 36

Using the and−or TrickVí dụ : Introducing the and−or Trick

>>> a = "first"

>>> b = "second"

>>> 1 and a or b

'first'

>>> 0 and a or b

'second'

•• Cú pháp này giống biểu thức " bool ? a : b " trong C . Tòan bộ biểu thức được ước lương từ trái sang phải , vì vậyand được mặc đinh đầu tiên .

•• 0 và 'first' ước lượng là false , và sau đó 0 or 'second' ước lượng 'second'.Ví dụ : When the and−or Trick Fails

>>> a = ""

>>> b = "second"

>>> 1 and a or b

'second'

• a là một chuỗi rỗng , Python cân nhắc false trong một boolean context, 1 và ược lượng , vàsau đó hoặc 'second' mặc định 'second'.

Vi dụ : Using the and−or Trick Safely

>>> a = ""

>>> b = "second"

>>> (1 and [a] or [b])[0]

• Khi [a] không là một danh sách rổng , nó thì không bao giờ false . Ngay cả nếu a là 0 hoặc vài giá trị false khác ,danh sách [a] là true bởi vì nó có một phần tử .

Using lambda functionsPython hổ trợ một cú pháp quan trọng mà để bạn định nghĩa một hàng , hàm nhỏ trên fly . Được mượn từ Lisp,Những cái này được gọi là hàm lambda mà có thể được dùng bất cứ đâu khi một hàm được đòi hỏi .Ví dụ : Introducing lambda Functions

>>> def f(x):

... return x*2

...

>>> f(3)

6

>>> g = lambda x: x*2

>>> g(3)

6

>>> (lambda x: x*2)(3)

•• Đây là một hàm lambda , trông giốn như một hàm thông thường trên nó . Chú ý cú pháp tóm tắt ở đây : Không códấu ngoặc đơn quanh danh sách tham số , và từ khóa return bỏ qua . Dù vậy , hàm không tên , nhưng nó có thểđược gọi thông qua biến nó assign.

•• Bạn có thể sử dụng hàm lambda không cần assign một biến .

Page 39: Học python

Chương IV 37

Real−World lambda FunctionsHere are the lambda functions in apihelper.py:

processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)

Ví dụ : split With No Arguments

>>> s = "this is\na\ttest"

>>> print s

this is

a test

>>> print s.split()

['this', 'is', 'a', 'test']

>>> print " ".join(s.split())

'this is a test'

•• Đây là một chuỗi nhiều dòng , được định nghĩa bởi kí tự escape thay vì ba đấu ngoặc•• split không có bất cứ tham số . Vì vậy tách dựa trên ' ', '\n', '\t' .•• Bạn có thể sử dụng chuổi " " nối chuổi vừa được tách .Hàm info thật sự làm với 3 hàm lambda , splits và and-or tricks ?

processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)

Putting it all togetherThis is the meat of apihelper.py:

print "\n".join(["%s %s" %

(method.ljust(spacing),

processFunc(str(getattr(object, method).__doc__)))

for method in methodList])

Ví dụ : Getting a doc string Dynamically

>>> import odbchelper

>>> object = odbchelper

>>> method = 'buildConnectionString'

>>> getattr(object, method)

<function buildConnectionString at 010D6D74>

>>> print getattr(object, method).__doc__

Build a connection string from a dictionary of parameters.

Returns string.

•• Trong hàm info , object là đối tượng bạn đang lấy sự giúp đở , truyền trong như một tham số .•• Trong khi bạn đang lặp xuyên qua danh sách , phương thức là tên của phương thức hiện tại .•• Sử dụng hàm getattr , bạn dang lấy một tham chiếu tới phương thức của đối tương trong module .•• Bây giờ là phương thức in doc string thì dể dàng .Ví dụ. Introducing ljust

>>> s = 'buildConnectionString'

>>> s.ljust(30)

'buildConnectionString '

Page 40: Học python

Chương IV 38

>>> s.ljust(20)

'buildConnectionString'

•• ljust thêm vào chuổi với khỏang trống với độ dài được truyền .•• Nếu độ dài được đưa vào thì nhỏ hơn độ dài của chuỗi , ljust sẽ đơn giản trả về chuỗi không bị thay đổi .Ví dụ : Printing a List

>>> li = ['a', 'b', 'c']

>>> print "\n".join(li)

a

b

c

•• Đây là cách hửu dụng để gỡ rối với trick . Và trong python , bạn luôn luôn làm việc với danh sách .Bây giờ bạng có thể hiểu dòng code sau .

print "\n".join(["%s %s" %

(method.ljust(spacing),

processFunc(str(getattr(object, method).__doc__)))

for method in methodList])

Summary•• Định nghĩa và gọi một hàm với tham số tùy chọn và xác định .•• Sử dụng str để cưởng bức bất cứ giá trị tùy ý nào vào trong biểu diển chuổi .•• Sử dụng getattr để lấp tham chiếu tới hàm và thuộc tính động .•• Mở rộng danh sách , cú pháp để lọc danh sách .• Nhận diện and−or trick và dùng nó an tòan .•• Định nghĩa hàm lambda.•• Assigning functions vào biến và gọi hàm bằng tham chiếu qua biến đó .

Page 41: Học python

Chương V 39

Chương V

Diving inĐọc doc strings của module , lớp , hàm để lấy overview của chương trình này nó làm việc như thế nào . Thôngthường , đừng lo lắng về những vấn đề bạn không hiểu .Vì dụ : fileinfo.pyCó thể download ví dụ từ đây (http:/ / diveintopython. org/ download/ diveintopython−examples−5. 4. zip)

"""Framework for getting filetype−specific metadata. Instantiate appropriate class with filename. Returned object acts like a

dictionary, with key−value pairs for each piece of metadata. import fileinfo

info = fileinfo.MP3FileInfo("/music/ap/mahadeva.mp3")

print "\\n".join(["%s=%s" % (k, v) for k, v in info.items()])

Or use listDirectory function to get info on all files in a directory.

for info in fileinfo.listDirectory("/music/ap/", [".mp3"]):

Framework có thể được mở rộng bởi thêm những lớp cho các file riêng biệt , HTMLFileInfo, MPGFileInfo, returndata.replace("\00", "").strip()

class FileInfo(UserDict):

"store file metadata"

def __init__(self, filename=None):

UserDict.__init__(self)

self["name"] = filename

class MP3FileInfo(FileInfo):

"store ID3v1.0 MP3 tags"

tagDataMap = {"title" : ( 3, 33, stripnulls),

"artist" : ( 33, 63, stripnulls),

"album" : ( 63, 93, stripnulls),

"year" : ( 93, 97, stripnulls),

"comment" : ( 97, 126, stripnulls),

"genre" : (127, 128, ord)}

def __parse(self, filename):

"parse ID3v1.0 tags from MP3 file"

self.clear()

try:

fsock = open(filename, "rb", 0)

try:

fsock.seek(−128, 2) tagdata = fsock.read(128)

finally:

fsock.close()

if tagdata[:3] == "TAG":

for tag, (start, end, parseFunc) in self.tagDataMap.items():

self[tag] = parseFunc(tagdata[start:end])

Page 42: Học python

Chương V 40

except IOError:

pass

def __setitem__(self, key, item):

if key == "name" and item:

self.__parse(item)

FileInfo.__setitem__(self, key, item)

def listDirectory(directory, fileExtList):

"get list of file info objects for files of particular extensions"

fileList = [os.path.normcase(f) for f in os.listdir(directory)]

fileList = [os.path.join(directory, f)for f in fileList

if os.path.splitext(f)[1] in fileExtList]

def getFileInfoClass(filename, module=sys.modules[FileInfo.__module__]):

"get file info class from filename extension"

subclass = "%sFileInfo" % os.path.splitext(filename)[1].upper()[1:]

return hasattr(module, subclass) and getattr(module, subclass) or FileInfo

return [getFileInfoClass(f)(f) for f in fileList]

if __name__ == "__main__":

for info in listDirectory("/music/_singles/", [".mp3"]):

print "\n".join(["%s=%s" % (k, v) for k, v in info.items()])

print

•• Đây là chương trình output phụ thuộc trên files trên đỉa cứng của bạn . Để lấy luồng xuất có nghĩa ,bạn sẽ cầnthay đổi đường dẫn thư mục tới thư mục trên máy của bạn .

album= artist=Ghost in the Machine title=A Time Long Forgotten (Concept genre=31name=/music/_singles/a_time_long_forgotten_con.mp3 year=1999 comment=http:/ / mp3. com/ ghostmachinealbum=Rave Mix artist=***DJ MARY−JANE*** title=HELLRAISER****Trance from Hell genre=31name=/music/_singles/hellraiser.mp3 year=2000 comment=http:/ / mp3. com/ DJMARYJANE album=Rave Mixartist=***DJ MARY−JANE*** title=KAIRO****THE BEST GOA genre=31 name=/music/_singles/kairo.mp3year=2000

Importing Modules Using from module importPython có 2 cách để import modules . Cả hải thì hữu dụng , và bạn sẽ biết khi nào dùng cài nào .Đây là cách cơ bản from module import syntax :•• from module import * trong Python thì giống như sử dung module trong Perl .•• from module import * trong Python thì giống như import module.* trong java .Ví dụ : import module vs. from module import

>>> import types

>>> types.FunctionType

<type 'function'>

>>> FunctionType

Traceback (innermost last):

File "<interactive input>", line 1, in ?

NameError: There is no variable named 'FunctionType'

>>> from types import FunctionTyp

>>> FunctionType

Page 43: Học python

Chương V 41

<type 'function'>

•• module types không chứa phương thức , nó chỉ có thuộc tính cho mổi đối tương Python .•• FunctionType của chính nó thì không được định nghĩa trong không gian namespace .•• Cú pháp này imports thuộc tính FunctionType từ lọai module vào trong vùng không gian .•• Bây giờ FunctionType có thể truy cậy trực tiếp , không cần tham chiếu tới types.Khi nào bạn sử dụng from module import ?•• Nếu bạn truy cập thuộc tính và phương thức thường hơn•• Nếu bạn muốn chọn lọc import vài thuộc tính và phương thức nhưng không phải cái khác , sử dụng from module

import.•• Nếu module chứa thuộc tính hay hàm với cùng tên như là một trong module của bạn , bạn cần dùng module tránh

xung đột tên .

Defining classesPython thì hòan tòan hướng đối tượng : bạn có thể đinh nghĩa lớp của chính mình , kế thừa từ lớp được xây dựng bởichính bạn.Ví dụ : The Simplest Python Class

class Loaf:

pass

•• Tên của lớp này là Loaf , và nó không kế thừa tứ bất cứ lớp nào khác . Tên lớp thường viết Hoa, nhưng điều nàychỉ là một quy ước ,không đòi hỏi.

•• Lớp này không định nghĩa bất cứ thuộc tính hay phương thức nào , nhưng về cú pháp , cần thiết để làm một vàiđiều gì đó trong định nghĩa , vì vậy bạn dùng pass . Đây là một từ dành riêng của python mà có nghĩa là "đi tiếp ,không làm gì khác ở đây ". Nó là một phát biểu mà không làm gì cả .

•• Nếu như bạn đóan được điều này , nhưng mỗi thứ trong lớp thì phải thụt vào , giống như code trong hàm , ifstatement, for loop, ...

Ví dụ : Defining the FileInfo Class

from UserDict import UserDict

class FileInfo(UserDict):

Trong python , lớp ông bà của lớp thì đơn giản là được liệt kê vào trong ngoặc đơn lập tức sau tên lớp . Vì vậy lớpFileInfo được kế thừa từ lớp UserDict (được import từ module UserDict). UserDict là một lớp mà họat động giốngmột từ điển .

Initializing and Coding ClassesVí dụ : Initializing the FileInfo Class

class FileInfo(UserDict):

"store file metadata"

def __init__(self, filename=None):

•• Lớp có thể doc strings , giống module và hàm . __init__ thì được gọi lập tức sau một đối tương của lớp được tạo .Ví dụ : Coding the FileInfo Class

class FileInfo(UserDict):

"store file metadata"

Page 44: Học python

Chương V 42

def __init__(self, filename=None):

UserDict.__init__(self)

self["name"] = filename

•• Vài ngôn ngữ lập trình hướng đối tượng giả giống Powerbuilder có một khái niệm "extending" constructors vàcác sự kiện khác , Nơi mà phương thức ông bà được gọi một cách tự động trước khi phương thức con cháu đượcthực thi . Python không phải làm điều này ; Bạn phải luôn luôn gọi rỏ ràng những hàm thích hợp trong lớp tổ tiên.

•• Lớp họat động giống như một thư viện .

Knowing When to Use self and __init__Khi định nghĩa lớp phương thức của bạn , bạn cần liệt kê rỏ ràng self như là tham số đầu tiên phương thúc ,bao gồm__init__ . Khi bạn gọi một phương thức của lớp tổ tiên từ trong lớp của bạn ,bạn cần phải bao gồm tham số self .Nhưng khi bạn gọi lớp phương thức của bạn từ bên ngòai , bạn không cần đặc tả bất cứ thứ gì cho tham số self .Python tự động thêm tham chiếu self cho bạn . Nó thì không thật sự mâu thuẩn , nhưng nó có thể xuất hiện mâuthuẩn bởi vì nó tin cậy trên sự khác nhau ( giữa phương thức giới hạn và không giới hạn) . Tất cả lớp trong Pythonlàm việc cùng 1 cách tương tự , vì vậy một khi bạn đã học một , bạn học hết tất cả chúng . Nếu bạn quên mọi điềukhác , nhớ một điều , vì vậy tôi hưa nó sẽ dẫn bạn lên.Chú ý rằng phương thức __init__ không bao giờ trả về giá trị .

Instantiating classesThí dụ cụ thể lớp trong Python thì thẵng thắng . Để thuyết minh một lớp , đơn giản gọi lớp như là nó thì ở trong hàm, truyền vào tham số cho phương thức __init__ . Giá trị trả về sẽ là đối tượng được tạo mới .Ví dụ . Creating a FileInfo Instance

>>> import fileinfo

>>> f = fileinfo.FileInfo("/music/_singles/kairo.mp3")

>>> f.__class__

<class fileinfo.FileInfo at 010EC204>

>>> f.__doc__

'store file metadata'

>>> f

{'name': '/music/_singles/kairo.mp3'}

Bạn đang tạo một đối tượng của lớp FileInfo (được định nghĩa trong module fileinfo ) và quy cho đối tượng được tạomới tới biến f . Bạn đang truyền một tham số , /music/_singles/kairo.mp3 , sẽ kết thúc như là tham số filename trongphương thứ __init__ của FileInfo . Mỗi lớp instance có một thuộc tính built-in , __class__ ( chú ý rằng sự miêu tảđiều này bao gồm địa chỉ vật lý của instance trong máy )Bạn có thể truy cậy doc string của instance như là với một hàm hay một module . Tất cả instance của class chia sẽdoc string giống nhau .

Page 45: Học python

Chương V 43

Garbage CollectionNếu tạo instances mới thì dể dàng , thì hủy chúng dể dàng hơn . Không có nhu cầu giải phóng instance rỏ ràng . Vìvậy chúng được giải phóng một cách tự động khi biến được ấn định thì ngòai phạm vi . are rare in Python.Ví dụ : Trying to Implement a Memory Leak

>>> def leakmem():

... f = fileinfo.FileInfo('/music/_singles/kairo.mp3')

...

>>> for i in range(100):

... leakmem()

•• Mỗi làn hàm leakmen được gọi , bạn đang tao một instance của FileInfo và ấn định nó tới biến f , là một biến điaphương trong hàm . Sau khi hàm kết thúc , f được giải phóng .

•• Không vấn đề , bao nhiêu lần bạn gọi hàm leakmen , nó sẽ không bao giờ leak memory, bởi vì mỗi lần , python sẽhủy lớp FileInfo mới trước khi trả về leakmem . Giới hạn của kỉ thuật "garbage collection " được "referencecounting". Python giữ một danh sách tham chiếu tới mỗi một instance được tạo . Trong ví dụ trên , chỉ có mộttham chiếu tới "FileInfo instance" , biến f địa phương . Khi hàm kết thúc , biến f the variable f ngoài phạm vi , vìvậy bộ đếm tham chiếu xuống 0 , và Python hủy tự động instance .

Exploring UserDict : A wrapper classNhư bạn đã xem , FileInfo là một lớp mà họat động giống một dictionanry . Xa hơn , chúng ta xem lớp UserDicttrong Userm module , là tổ tiên của lớp FileInfor . Điều này thì không đặc biệt , lớp được viết trong python và đượclưu trử trong một file .py . Giống bất cứ đọan code nào khác . Trong trường hợp đặc biệt , nó lưu trữ trong libdirectory trong cài đặt python của bạn .Ví dụ : Defining the UserDict Class

class UserDict:

def __init__(self, dict=None):

self.data = {}

if dict is not None: self.update(dict)

•• Chú ý rằng UserDict là lớp cơ sở , không kế thừa từ bất kì lớp khác .•• Phương thức __init__ này bạn viết đè lên lớp FileInfo . Chú ý rằng danh sách tham số trong lớp tổ tiên này thì

khác biệt hơn . Điều đó thì ổn ; mỗi lớp con có thể có tập hợp tham số của chính nó , củng lâu như là nó gọi tổ tiênvới tham số đúng . lớp tổ tiên có một cách để khởi tạo giá trị ( bởi truyền một dictionary trong tham sốdict)FileInfo không sử dụng .

•• Python hổ trợ thuộc tính dử liệu ( gọi "instance variables" trong java và Powerbuilder , và "member variables"trong C++ ) . Thuộc tính dữ liệu là những miếng dữ liệu được giử lại một instance của một lớp . Trong trường hợpnày , mỗi một instance của UserDict sẽ có một thuộc tính dữ liệu . Để tham chiếu thuộc tính này từ code bênngòai lớp . Với quy ước , tất cả thuôc tính dự liệu thì được khởi tạo tới giá trị hợp lí trong phương thức __init__ .Tuy nhiên , điều này thì không nhất thiết đòi hỏi ,kể từ thuộc tính dữ liệu , giống biến địa phương .

•• Phương thức update là một sao chép . Nó sao chép tất cả khóa và giá trị từ dictionary tới cái khác. Điều này khôngrỏ ràng .

Ví dụ : UserDict Normal Methods

def clear(self): self.data.clear()

def copy(self):

if self.__class__ is UserDict:

Page 46: Học python

Chương V 44

return UserDict(self.data)

import copy

return copy.copy(self)

def keys(self): return self.data.keys()

def items(self): return self.data.items()

def values(self): return self.data.values()

•• clear một lớp phương thức bình thường , nó thì sẳn sàng để được gọi bởi bất cứ ai, bất cứ lúc nào. chú ý rằng clear, giống tất cả phương thức lớp , có self như nó là tham số đầu tiên ( Nhớ rằng bạn không bao gồm self khi bạn gọiphương thức

Ví dụ : Inheriting Directly from Built−In Datatype dict

class FileInfo(dict):

"store file metadata"

def __init__(self, filename=None):

self["name"] = filename

• Tham chiếu đầu tiên là cái mà bạn không cần import vào module UserDict , kế từ khi dict là một a built−indatatype và luôn sẳn sàng. Tham chiếu thức hai là cái mà bạn đang kế thừa từ dict trực tiếp, thay vì từUserDict.UserDict.

•• Tham số thứ ba là subtle nhưng quan trọng . Bởi vì cách UserDict làm việc bên trong , nó đòi hỏi bạn để gọi bằngtay .

Special class methodsThêm vào lớp phương thức bình thường , có một số phương thức đặc biệt mà lớp Python có thể định nghĩa . Thay vìgọi trực tiếp bởi code ( giống phương thức bình thường ) , phương thức đặc tả được gọi cho bạn bởi python trongtrường hợp đặc biệt .

Getting and Setting ItemsVí dụ : The __getitem__ Special Method

def __getitem__(self, key): return self.data[key]

>>> f = fileinfo.FileInfo("/music/_singles/kairo.mp3")

>>> f

{'name':'/music/_singles/kairo.mp3'}

>>> f.__getitem__("name")

'/music/_singles/kairo.mp3'

>>> f["name"]

'/music/_singles/kairo.mp3'

•• Phương thức đặc biết __getitem__ trông khá đơn giản . Giống như phương thức clear bình thướng , keys, andvalues. Bạn có thể gọi phương thức __getitem__ trực tiếp , nhưng trong thực hành bạn sẽ không thật sự làm điềuđó ; Cách đúng để sử dụng __getitem__ là Python gọi nó cho bạn .

•• Điều này giống cú pháp bạn sẽ dùng để lấy giá trị dictionary , và trong thực tế nó trả về giá trị bạn mong muốn .Không chỉ bạn có thể gọi nó bởi chính bạn , bạn có thẻ lấy Python để gọi nó cho bạn với sử dụng cú pháp đúng .

Ví dụ : The __setitem__ Special Method

Page 47: Học python

Chương V 45

def __setitem__(self, key, item): self.data[key] = item

>>> f

{'name':'/music/_singles/kairo.mp3'}

>>> f.__setitem__("genre", 31)

>>> f

{'name':'/music/_singles/kairo.mp3', 'genre':31}

>>> f["genre"] = 32

>>> f

{'name':'/music/_singles/kairo.mp3', 'genre':32}

•• Giống phương thức __getitem__ , __setitem__ đơn giản gọi một lần tới dictionary thật self.data để nó làm việc .Và giống __getitem__, bạn sẽ muốn gọi nó một cách bình thường trực tiếp giống cái này; Python gọi __setitem__cho bạn khi bạn dùng cú pháp đúng .

Ví dụ : Overriding __setitem__ in MP3FileInfo

def __setitem__(self, key, item):

if key == "name" and item:

self.__parse(item)

FileInfo.__setitem__(self, key, item)

•• Chú ý rằng phương thức __setitem__ thì được định nghĩa một cách chính xác cùng cách như phương thức tổ tiên.Điều này quan trọng , kể từ khi Python gọi phương thức cho bạn , và nó mong chờ nó được định nghĩa với một sốnumber của tham số .

Advanced Special class methodsPython có nhiều phương thức đặc biệt như __getitem__ và __setitem__ . Đôi khi chúng để bạn bắt chước và bạnkhông biết .Ví dụ này chỉ vài phương thức đặc biệt trong UserDict .Ví dụ : More Special Methods in UserDict

def __repr__(self): return repr(self.data)

def __cmp__(self, dict):

if isinstance(dict, UserDict):

return cmp(self.data, dict.data)

else:

return cmp(self.data, dict)

def __len__(self): return len(self.data)

def __delitem__(self, key): del self.data[key]

• __repr__ là một phương thức đặc biệt mà được gọi khi bạn gọi repr(instance). hàm repr là một hàm built−in trả vềmột chuổi miêu tả đối tượng . Nó làm việc trên bất cứ đối tượng nào , không chỉ lớp instances. Bạn đã quen thuộctường tận với rept rồi ,mà bạn không biết . Trong tương tác window , khi bạn gỏ một tên biến và nhấn ENTER ,Python sử dụng repr để hiển thị giá trị của biến . Tạo một từ điển d với vài dử liệu và sau đó in repr(d) để thấychính bạn .

•• __cmp__ được gọi khi bạn so sánh lớp instances . Trong phát sinh , bạn có thể so sánh bất cứ đối tượng Python ,không chỉ lớp instances , bởi sử dụng == . Có luật để định nghĩa built-in datatypes . Trong instance , dictionariesthì bằng khi chúng có cùng độ khóa và giá trị . Chuỗi thì bằng khi chúng thì cùng độ dài và chứa những kí tự tuầntự giống nhau . Trong lớp instances , bạn có thể định nghĩa phương thức __cmp__ và code so sánh luận lý của

Page 48: Học python

Chương V 46

chính bạn và sau đó bạn có thể dùng == để so sánh instances của lớp của bạn và Python sẽ gọi phương thức đặcbiệt __cmp__ cho bạn .

•• __len__ được gọi khi bạn gọi len(instance) , hàm len là một hàm built-in mà trả về độ dài của đối tượng . __len__làm việc trên bất cứ đối tượng mà có độ dài . len của một chuổi là số kí tự của nó . len của từ điển là số khóa củanó . len của danh sách hay tuple là số phần tử của nó . cho lớp instances , định nghĩa phương thức __len__ và codetính tóan chiều dài của chính bạn , và khi gọi len(instance) thì Python sẽ gọi phương thúc đặc biệt __len__ chobạn .

•• __delitem__ được gọi khi bạn gọi del del instance[key], mà bạn có thể nhớ như là cách để delete phần tử riêng lẻtừ từ điển . Khi bạn dùng del trong lớp instance , Python gọi phương thức __delitem__ cho bạn .

Introducing class AttributesVí dụ : Introducing Class Attributes

class MP3FileInfo(FileInfo):

"store ID3v1.0 MP3 tags"

tagDataMap = {"title" : ( 3, 33, stripnulls),

"artist" : ( 33, 63, stripnulls),

"album" : ( 63, 93, stripnulls),

"year" : ( 93, 97, stripnulls),

"comment" : ( 97, 126, stripnulls),

"genre" : (127, 128, ord)}

>>> import fileinfo

>>> fileinfo.MP3FileInfo

<class fileinfo.MP3FileInfo at 01257FDC>

>>> fileinfo.MP3FileInfo.tagDataMap

{'title': (3, 33, <function stripnulls at 0260C8D4>),

'genre': (127, 128, <built−in function ord>), 'artist': (33, 63, <function stripnulls at 0260C8D4>),

'year': (93, 97, <function stripnulls at 0260C8D4>),

'comment': (97, 126, <function stripnulls at 0260C8D4>),

'album': (63, 93, <function stripnulls at 0260C8D4>)}

>>> m = fileinfo.MP3FileInfo()

>>> m.tagDataMap

{'title': (3, 33, <function stripnulls at 0260C8D4>),

'genre': (127, 128, <built−in function ord>), 'artist': (33, 63, <function stripnulls at 0260C8D4>),

'year': (93, 97, <function stripnulls at 0260C8D4>),

'comment': (97, 126, <function stripnulls at 0260C8D4>),

'album': (63, 93, <function stripnulls at 0260C8D4>)}

•• MP3FileInfo là lớp của chính nó , không bất cứ instance đặc biệt của lớp .•• tagDataMap là một thuộc tính của lớp : thật vậy , một thuộc tính của lớp . Nó thì sẵn sàng trước khi tạo bất kì

instances của lớp .Ví dụ : Modifying Class Attributes

>>> class counter:

... count = 0

Page 49: Học python

Chương V 47

... def __init__(self):

... self.__class__.count += 1

...

>>> counter

<class __main__.counter at 010EAECC>

>>> counter.count

0

>>> c = counter()

>>> c.count

1

>>> counter.count

1

>>> d = counter()

>>> d.count

2

>>> c.count

2

>>> counter.count

•• count là một thuộc tính của lớp counter .•• __class__ là một thuộc tính built-in của mỗi lớp instance . Nó là một tham chiếu tới lớp mà self là một instance

của ( trong trường hợp này , lớp counter ).•• Vì vậy count là một thuộc tính lớp , nó thì sẵn sàng thông qua tham chiếu trực tiếp tới lớp . Trước khi bạn tạo bất

kì instances của lớp .•• Tạo một instance của lớp , gọi phương thức __init__ , cái mà làm tặng thuộc tính count của lớp lên một . Điều này

ảnh hưởng lên lớp của chính nó , không chỉ tạo mới instance .•• Tạo một instance thứ hai sẽ tặng thuộc tính count lên lần nửa . Chú ý , thuộc tính lớp được chia sẽ bơi lớp và tất

cả instances của lớp .

Private FunctionsGiống như hầu hết các ngôn ngữ , Python có khái niệm phần tử riêng ( private elements ) :•• Hàm riêng , không thể được gọi từ bên ngòai module của chúng .•• Phương thức lớp riêng , không thể được gọi từ bên ngòai lớp của chúng .•• Thuộc tính riêng , không thể truy cậy từ bên ngòai lớp của chúng ·Không giống như phần đông ngôn ngữ , không chắc Hàm , phương thức hay thuộc tính của Pythong là private haypublic được xác định hòan tòan bởi tên của nó .Nếu tên của một hàm Python , phương thức lớp hay thuộc tính bắt đầu với(nhưng không kết thúc với ) hai đườnggạch dưới , nó là private , mọi thứ khác là public . Python không có khái niệm lớp phương thức protected ( truy cậpchỉ trong lớp của chính nó và các lớp con cháu ). Phương thức lớp thì một trong hai private hay public .Ví dụ : Trying to Call a Private Method

>>> import fileinfo

>>> m = fileinfo.MP3FileInfo()

>>> m.__parse("/music/_singles/kairo.mp3")

Traceback (innermost last):

File "<interactive input>", line 1, in ?

AttributeError: 'MP3FileInfo' instance has no attribute '__parse'

Page 50: Học python

Chương V 48

•• Nếu bạn cố gắng gọi phương thức riêng , Python sẽ ném một ngọai lệ , nói rằng cái đó là phương thức không tồntại . Dĩ nhiên là nó có tồn tại , nhưng nó là private , vì vậy nó không thể truy cậo bên ngòai lớp . Không có cái gìtrong Python thật sự là private . Bạn có thể truy cập phương thức __parse của lớp MP3FileInfo bởi tên_MP3FileInfo__parse . Công nhận điều này thì thú vị , nhưng hứa không bao giờ làm điều đó trong code thật sự .

Bài tập căn bản

Nhập,xuất,tính toán

Bài 1.1""" Viết chương trình nhập vào năm sinh, in ra tuổi, ví dụ nhập 1984 in ra: Ban sinh năm 1984, vay ban 19 tuoi. """

#Chuong trinh : Nhap nam sinh Xuat tuoi

import time

x=time.localtime()

print x[0]

def Xuat_tuoi(Namsinh):

x=time.localtime()

a=x[0]-Namsinh

if a==0:

print "Tuoi cua ban la :",a+1

elif (a<0):

print "Tuoi nay chua ton tai"

else:

print "Tuoi cua ban la :",a

NS=int(raw_input("Nhap nam sinh : "))

Xuat_tuoi(NS)

Bài 1.2import math

def Tinh(R):

if R<0:

print "Ban kinh khong nho hon 0"

print "Ban nhap khong hop le"

else:

CV=2*R*math.pi

DT=R*R*math.pi

print "Chu vi la :",CV

print "Dien tich la :",DT

print "-------Tinh Chu Vi, Dien Tich Hinh Tron---------"

r=float(raw_input("Nhap ban kinh hinh tron: "))

Tinh(r

Page 51: Học python

Bài tập căn bản 49

Bài 1.4import math

def Bai_1_4(R,h):

S_DAY=R**2*math.pi

S_XQ=2*R*h*math.pi

V=S_DAY*h

if (R<0)or(h<0):

print "Ban nhap khong hop le"

else:

print "Dien tich day la :",S_DAY

print "Dien tich xung quang la :",S_XQ

print "The tich la :",V

print"-----Tinh Dien Tich,The Tich Hinh Tru Tron-------"

if __name__=="__main__":

r=float(raw_input("Nhap ban kinh :"))

h=float(raw_input("Nhap chieu cao :"))

Bai_1_4(r,h)

Bài 1.5import math

def Bai_1_5(x):

y1=4*(x*x+10*math.pow(x, 1.5)+3*x+1)

y2=(math.sin(math.pi*x*x)+math.sqrt(x*x+1))/(math.exp(2*x)+math.cos((math.pi/4)*x))

print "Y1 = ",y1

print "Y2 = ",y2

print "------Tinh gia tri bieu thuc------------- "

x=float(raw_input("Nhap so thuc X : "))

Bai_1_5(x)

Bài 1.6import math

def Bai_1_6(n):

a=[10,5,2,1]

for i in a[:]:

so_to=n/i

print "Tien",i,"d co" , so_to,"to"

n=n%i

if __name__=="jfkjfk__main__":

N=int(raw_input("Nhap so tien : "))

Bai_1_6(N)

Page 52: Học python

Bài tập căn bản 50

Bài 1.7#Chuong trinh tinh tong cac chu so cua mot so nguyen

import math

def Bai_1_7(n):

s=0

while (n/10):

s+=n%10

n=n/10

return s+n;

if __name__=="__main__":

N=int(raw_input("Nhap 1 so nguyen :"))

print Bai_1_7(N)

Cấu trúc rẽ nhánh

Bài 2.1#Chuong trinh sap tang 3 so nguyen

def Bai_2_1(a,b,c):

if (a>=b):

if(b>=c):

print "ket qua :",c,b,a

else:

if(a>=c):

print "ket qua :",b,c,a

print "ket qua :",b,a,c

else: #a<b

if(b<=c):

print "ket qua :",a,b,c

else:#a<b,c<b

if(c<=a):

print "ket qua :",c,a,b

else:

print "ket qua :",a,c,b

if __name__=="__main__":

a=int(raw_input("Nhap a :"))

b=int(raw_input("Nhap b :"))

c=int(raw_input("Nhap c :"))

Bai_2_1(a,b,c)

Page 53: Học python

Bài tập căn bản 51

Bài 2.2def Max(a,b,c,d):

max=a

if b>max :

max=b

if c>max :

max=c

if d>max:

max=c

return max

def Min(a,b,c,d):

min=a

if b<min:

min=b

if c<min :

min=c

if d<min:

min=c

return min

def Trung_gian(a,b,c,d):

max=Max(a,b,c,d)

min=Min(a,b,c,d)

if (max!=a)and(min!=a):

print "So trung gian :",a

if (max!=b)and(min!=b):

print "So trung gian :",b

if (max!=c)and(min!=c):

print "So trung gian :",c

if (max!=d)and(min!=d):

print "So trung gian :",d

if __name__=="__main__":

a=int(raw_input("Nhap a :"))

b=int(raw_input("Nhap b :"))

c=int(raw_input("Nhap c :"))

d=int(raw_input("Nhap d :"))

print "So Lon Nhat :", Max(a,b,c,d)

print "So Nho Nhat :", Min(a,b,c,d)

Trung_gian(a,b,c,d)

==Bài 2.3==

def Bai3(a,b,c):

if (a+b)>c and (a+c)>b and (b+c)>a and (a>0) and (b>0) and (c>0):

if(a==b)and (b==c):

return 0

elif((a*b+b*b==c*c)and(a==b))or((a*a+c*c==b*b)and(a==c))or((c*c+b*b==a*a)and(c==b)):

Page 54: Học python

Bài tập căn bản 52

return 1

elif(a==b)or(b==c)or(a==c):

return 2

elif((a*a==b*b+c*c)or(b*b==a*a+c*c)or(c*c==a*a+b*b)):

return 3

else:

return 4

else:

return 5

if __name__=="__main__":

a=int(raw_input("Nhap a :"))

b=int(raw_input("Nhap b :"))

c=int(raw_input("Nhap c :"))

r=['Tam giac deu','tam giac vuong can','tam giac can','tam giac vuong ','tam giac thuong','khong hop le']

i=Bai3(a,b,c)

print r[i]

Bài 2.4def Bai_2_4(km):

if km==1:

print "So tien phai tra la : 5000d"

else:

if km<=5:

print "So tien phai tra la :",((km-1)*4500+5000)

else:

if(km<120):

print "So tien phai tra la :",((km-5)*3500+4500*4+5000)

else:

print "So tien phai tra la :",((((km-5)*3500+4500*4+5000)*1/10))

if __name__=="__main__":

km=int(raw_input("Nhap so km da di :"))

Bai_2_4(km)

Bài 2.5def Bai5(BD,KT):

h=KT-BD # So gio truy cap

T=1 #Thanh tien

if((BD>=0)and(BD<=7)):

if h>=7:

T=(T*h*300*60)/0.15

else:

T=T*h*300

if((BD>7)and (BD<=17)):

if h>=6:

T=(T*h*400*60)/0.1

Page 55: Học python

Bài tập căn bản 53

else:

T=T*h*400

if((BD>17)and (BD<=24)):

if h>=4:

T=(T*h*350*60)*0.12

else:

T=T*h*350

return T

if __name__=="__main__":

BD=int(raw_input("Nhap thoi gian bat dau :"))

KT=int(raw_input("Nhap thoi gian ket thuc :"))

print "Thanh tien",Bai5(BD,KT)

Bài 2.6def formatStringInput(str):

return str[:len(str)-1]

def Bai_6(Ngay_thue,Loai_phong):

if(Ngay_thue<=12):

if Loai_phong=='A':

return Ngay_thue*250000

if Loai_phong=='B':

return Ngay_thue*200000

if Loai_phong=='C':

return Ngay_thue*150000

else:

if Loai_phong=='A':

return Ngay_thue*250000*0.1

if Loai_phong=='B':

return Ngay_thue*200000*0.08

if Loai_phong=='C':

return Ngay_thue*150000*0.08

if __name__=="__main__":

So_ngay=int(raw_input("Nhap so ngay thue :"))

Loai=(raw_input("Nhap loai phong:"))

strLP = formatStringInput (Loai)

print "Thanh tien",Bai_6(So_ngay,strLP)

Bài 2.7#chuong trinh nhap vao 1 thang xuat ra mua tuong ung

def Bai_2_7(m):

if(m<1)or(m>12):

print "Nhap thang khong hop le"

if(m>=1)and(m<=3):

Page 56: Học python

Bài tập căn bản 54

print "Mua xuan"

if(m>=4)and(m<=6):

print "Mua ha"

if(m>=6)and(m<=9):

print "Mua thu"

if(m>=10)and(m<=12):

print "Mua dong"

if __name__=="__main__":

M=int(raw_input("Nhap 1 thang trong nam :"))

Bai_2_7(M)

Page 57: Học python

Nguồn và người đóng góp vào bài 55

Nguồn và người đóng góp vào bàiChương I  Nguồn: http://vi.wikibooks.org/w/index.php?oldid=81493  Người đóng góp: AmieKim, Andre Engels, Thientan1, Thientan15, 4 sửa đổi vô danh

Chương II  Nguồn: http://vi.wikibooks.org/w/index.php?oldid=89703  Người đóng góp: AmieKim, Thientan1, Thientan15, 2 sửa đổi vô danh

Chương III  Nguồn: http://vi.wikibooks.org/w/index.php?oldid=67700  Người đóng góp: AmieKim, Thientan1, Thientan15, Thientan18

Chương IV  Nguồn: http://vi.wikibooks.org/w/index.php?oldid=67701  Người đóng góp: AmieKim, Thientan15, 5 sửa đổi vô danh

Chương V  Nguồn: http://vi.wikibooks.org/w/index.php?oldid=67691  Người đóng góp: AmieKim, Thientan15, 1 sửa đổi vô danh

Bài tập căn bản  Nguồn: http://vi.wikibooks.org/w/index.php?oldid=92263  Người đóng góp: AmieKim, 25 sửa đổi vô danh

Page 58: Học python

Nguồn, giấy phép, và người đóng góp vào hình 56

Nguồn, giấy phép, và người đóng góp vào hìnhHình:E01.PNG  Nguồn: http://vi.wikibooks.org/w/index.php?title=Tập_tin:E01.PNG  Giấy phép: không rõ  Người đóng góp: Thientan1Hình:001.PNG  Nguồn: http://vi.wikibooks.org/w/index.php?title=Tập_tin:001.PNG  Giấy phép: không rõ  Người đóng góp: Thientan1Hình:0002.png  Nguồn: http://vi.wikibooks.org/w/index.php?title=Tập_tin:0002.png  Giấy phép: không rõ  Người đóng góp: Thientan1Hình:E02.PNG  Nguồn: http://vi.wikibooks.org/w/index.php?title=Tập_tin:E02.PNG  Giấy phép: không rõ  Người đóng góp: Thientan1Hình:E03.PNG  Nguồn: http://vi.wikibooks.org/w/index.php?title=Tập_tin:E03.PNG  Giấy phép: không rõ  Người đóng góp: Thientan1Hình:E04.PNG  Nguồn: http://vi.wikibooks.org/w/index.php?title=Tập_tin:E04.PNG  Giấy phép: không rõ  Người đóng góp: Thientan1Hình:E05.PNG  Nguồn: http://vi.wikibooks.org/w/index.php?title=Tập_tin:E05.PNG  Giấy phép: không rõ  Người đóng góp: Thientan1Hình:E06.PNG  Nguồn: http://vi.wikibooks.org/w/index.php?title=Tập_tin:E06.PNG  Giấy phép: không rõ  Người đóng góp: Thientan1Hình:E07.PNG  Nguồn: http://vi.wikibooks.org/w/index.php?title=Tập_tin:E07.PNG  Giấy phép: không rõ  Người đóng góp: Thientan1Hình:E08.PNG  Nguồn: http://vi.wikibooks.org/w/index.php?title=Tập_tin:E08.PNG  Giấy phép: không rõ  Người đóng góp: Thientan1Hình:E09.PNG  Nguồn: http://vi.wikibooks.org/w/index.php?title=Tập_tin:E09.PNG  Giấy phép: không rõ  Người đóng góp: Thientan1

Page 59: Học python

Giấy phép 57

Giấy phépCreative Commons Attribution-Share Alike 3.0//creativecommons.org/licenses/by-sa/3.0/