SlideShare a Scribd company logo
1 of 59
Download to read offline
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
Nội dung
Bài
Chương I 1
Chương II 14
Chương III 17
Chương IV 29
Chương V 39
Bài tập căn bản 48
Chú thích
Nguồn và người đóng góp vào bài 55
Nguồn, giấy phép, và người đóng góp vào hình 56
Giấy phép Bài viết
Giấy phép 57
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ọn
version 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.c
gcc −pthread −c −fno−strict−aliasing −DNDEBUG −g −O3 −Wall −Wstrict−prototypes
−I. −I./Include −DPy_BUILD_CORE −o Parser/acceler.o Parser/acceler.c
gcc −pthread −c −fno−strict−aliasing −DNDEBUG −g −O3 −Wall −Wstrict−prototypes
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ổ Shell
Bâ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ôi
cò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.
Chương I 3
Viết Python Bằng Eclipse
Eclipse 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:
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
Chương I 5
Tạo Project
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:
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 :
Chương I 8
Chuỗi
Ngoài số, Python còn làm việc được với chuỗi, có thể được biểu hiện theo nhiều cách. Chúng có thể được kẹp trong
dấu nháy đơn, đôi:
>>> '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ột
dấu suỵt huyền là ký tự cuối cùng trên một dòng cho biết rằng dòng kế là sự nối tiếp của dòng này:
hello = "This is a rather long string containingn
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.
Chương I 9
Cho nên, ví dụ:
hello = r"This is a rather long string containingn
several lines of text much as you would do in C."
print hello
sẽ in:
This is a rather long string containingn
several lines of text much as you would do in C.
Hoặc, các chuỗi có thể được vây quanh trong một cặp nháy ba: """ hoặc . Cuỗi mỗi dòng không cần thêm dấu suỵt
huyền khi dùng nháy ba, và chúng sẽ có mặt trong chuỗi.
print """
Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to
"""
xuất ra:
Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to
Trình thông dịch in ra kết quả của các tác vụ chuỗi theo cùng cách như khi chúng được nhập vào: trong dấu nháy, và
với các ký tự dấu nháy hay đặc biệt khác được thoát nghĩa (escape) bằng dấu suỵt huyền, để hiện giá trị thực. Chuỗi
được kèm trong dấu nháy đôi nếu chuỗi chứa một dấu nháy đơn và không chứa dấu nháy đôi, ngoài ra nó sẽ được
chứa trong các dấu nháy đơn. (Câu lệnh print , được giải thích sau, có thể dùng để viết các chuỗi không có dấu nháy
hoặc thoát nghĩa.)
Các chuỗi có thể được nối với nhau với toán tử + , và được lặp lại với *:
>>> word = 'Help' + 'A'
>>> word
'HelpA'
>>> '<' + word*5 + '>'
'<HelpAHelpAHelpAHelpAHelpA>'
Hai chuỗi trực tiếp kế nhau được tự động nối với nhau; dòng đầu tiên bên trên có thể được biết "word = 'Help' 'A'";
việc này chỉ có tác dụng với hai chuỗi trực tiếp (string literal), không có tác dụng với các biểu thức chuỗi bất kỳ
khác:
>>> 'str' 'ing' # <- This is ok
'string'
>>> 'str'.strip() + 'ing' # <- This is ok
'string'
>>> 'str'.strip() 'ing' # <- This is invalid
File "<stdin>", line 1, in ?
'str'.strip() 'ing'
^
Chương I 10
SyntaxError: invalid syntax
Các chuỗi có thể được chỉ mục (subscript hoặc index); như trong C, ký tự đầu tiên của một chuỗi có chỉ mục 0.
Không có kiểu ký tự riêng; một ký tự chỉ đơn giản là một chuỗi có độ dài là một. Như trong Icon, chuỗi con có thể
được chỉ định theo cách viết cắt lát (slice notation): hai chỉ mục phân cách bởi một dấu hai chấm.
>>> word[4]
'A'
>>> word[0:2]
'He'
>>> word[2:4]
'lp'
Các chỉ mục cắt lát có giá trị mặc định hữu dụng; chỉ mục đầu tiên có giá trị mặc định là không, chỉ mục thứ hai mặc
định là kích thước của chuỗi đang bị cắt.
>>> word[:2] # The first two characters
'He'
>>> word[2:] # Everything except the first two characters
'lpA'
Không như C, các chuỗi Python không thể bị thay đổi. Phép gán vào một vị trí chỉ mục trong một chuỗi sẽ gây ra lỗi:
>>> word[0] = 'x'
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: object doesn't support item assignment
>>> word[:1] = 'Splat'
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: object doesn't support slice assignment
Tuy nhiên, việc tạo một chuỗi với nội dung gộp chung cũng dễ và hiệu quả:
>>> 'x' + word[1:]
'xelpA'
>>> 'Splat' + word[4]
'SplatA'
Đây là một tính chất bất biến hữu dụng khác của tác vụ cắt lát: s[:i] + s[i:] bằng s.
>>> word[:2] + word[2:]
'HelpA'
>>> word[:3] + word[3:]
'HelpA'
Các chỉ mục cắt lát giảm sinh (degenerate) được xử lý rất khéo: một chỉ mục quá lớn sẽ được thay bằng kích thước
chuỗi, một giới hạn trên nhỏ hơn giới hạn dưới trả về một chuỗi rỗng.
>>> word[1:100]
'elpA'
>>> word[10:]
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ông
phải cắt lát):
>>> word[-100:]
'HelpA'
>>> word[-10] # error
Traceback (most recent call last):
File "<stdin>", line 1, in ?
IndexError: string index out of range
Cách tốt nhất để nhớ hoạt động của cắt lát là nghĩ về các chỉ mục như đang trỏ vào giữa các ký tự, với cạnh trái của
ký tự đầu tiên là 0. Sau đó cạnh phải của ký tự cuối cùng của một chuỗi của n ký tự có chỉ mục n, ví dụ:
+---+---+---+---+---+
| H | e | l | p | A |
+---+---+---+---+---+
0 1 2 3 4 5
-5 -4 -3 -2 -1
Các số hàng đầu cho biết vị trí của các chỉ mục 0...5 trong chuỗi; dòng thứ hai cho biết các chỉ mục âm tương ứng.
Một lát từ i tới j chứa toàn bộ các ký tự giữa các cạnh đánh số 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ủa
word[1:3] là 2.
Hàm có sẵn len() trả về độ dài của một chuỗi:
>>> s = 'supercalifragilisticexpialidocious'
>>> len(s)
34
Chương I 12
Danh Sách
Python biết một số kiểu dữ liệu gộp (compound) , dùng để nhóm các giá trị với nhau. Kiểu linh hoạt nhất là danh
sách (list), có thể được viết như là một danh sách các giá trị phân cách bởi dấu phẩy ở giữa ngoặc vuông.
>>> a = ['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ủa
mộ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]
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
Chương II 14
Chương II
Đi vào Python
Python 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ải
phâ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.py
Nế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àm
Python 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ạn
interface/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ủa
nhữ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 python
trả 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ông
thì nó sẽ trả về một giá trị rỗng.
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ĩnh
Nó 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 động
Mộ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ểu
nă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ểu
integer, 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ấp
Mộ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. Trong
VBScript, 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ông
cầ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àm
Bạ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ủa
mộ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úng
bấ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ên
phả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. Đây
la 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ột
thuộc tính của hàm.
Mọi thứ là một đối tượng
Hà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.
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ặc
từ 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ặc
cá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ái
niệ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ạn
không thể chỉ gọi buildConnectionString, nó phải là odbchelper.buildConnectionString. Nếu bạn đã từng dùng các
lớ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ôn
ngữ 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àm
Perl, bạn xác nhận hàm của nó với module::function.
Nhập tìm đường dẫn
Trướ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ạn
import 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ên
trong 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ư sys
module đượ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êm
và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ết
lậ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 đối
tượ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ượng
buộ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. Trong
Python, đị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ó đối
tượ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 được
thô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 đối
tượng, Hàm là các đối tượng, mudule cũng là các đối tượng.
Chương III 17
Chương III
Khá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 ta
hiể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ỗi
thứ đề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ương
phá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àng
minh 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ương
trì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àm
gì để 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ũng
có 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âm
củ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ới
quanh 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ủa
mì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òn
số 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 tin
nhâ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ằng
chú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ình
hướ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ới
cá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ới
theo 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. Đây
là 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 theo
mộ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ăng
mớ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ác
nhà 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ác
quyể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ột
phầ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
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ệu
củ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ể (Instance
variable). 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 được
gọ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ào
nhậ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ác
biế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 định
bở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ắn
bó đó, 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ông
phả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ương
trì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ải
Trong 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.
Class
Chỉ 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ũng
như 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ủa
class 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ột
class 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ư trong
Smalltalk, 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ợp
cụ thể của class.
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 ảnh
hưởng đối với ý nghĩa của mã Python có sử dụng các đối tượng khả biến như danh sách, từ điển, và đa số các kiểu
thể hiện các vật ngoài chương trình (tập tin, cửa sổ, v.v...). Nó thường được dùng vì tên lóng có tác dụng như là con
trỏ theo một vài khía cạnh nào đó. Ví dụ, truyền một đối tượng vào một hàm rẻ vì chỉ có con trỏ là được truyền, và
nếu một hàm thay đổi một đối tượng được truyền vào, thì nơi gọi sẽ thấy các thay đổi đó -- thay vì cần hai kiểu
truyền thông số như trong Pascal.
Phạm vi trong Python và vùng tên
Trước khi giới thiệu lớp, chúng ta sẽ cần hiểu phạm vi (scope) và vùng tên (namespace) hoạt động như thế nào vì các
định nghĩa lớp sẽ sử dụng chúng. Kiến thức về vấn đề này cũng rất hữu dụng với những nhà lập trình Python chuyên
nghiệp.
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ên
như: 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ác
tê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ụ hai
module 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êm
tiề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, real
là 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 trong
mô-đ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ác
thuộ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ể được
xó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 được
tạ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át
ra. Các câu lệnh được thực thi bởi lời gọi ở lớp cao nhất của trình thông dịch, vì đọc từ một kịch bản hoặc qua tương
tác, được coi như một phần của 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ật
ra cũng tồn tại trong một module; được gọi là __builtin__.)
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 vi
lồng nhau mà vùng tên của chúng có thể được truy cập trực tiếp: phạm vi bên trong cùng, được tìm trước, chứa các
tên nội bộ; các vùng tên của các hàm chứa nó, được tìm bắt đầu từ phạm vi chứa nó gần nhất (nearest enclosing
scope); phạm vi giữa (middle scope), được tìm kế, chứa các tên toàn cục của module; và phạm vi ngoài cùng (được
tìm sau cùng) là vùng tên chứa các tên có sẵn.
Nếu một tên được khai báo là toàn cục, thì mọi tham chiếu hoặc phép gán sẽ đi thẳng vào phạm vi giữa chứa các tên
toàn cục của 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ử khi
vào các biến đó sẽ tạo một biến cục bộ mới trong phạm vi trong vùng, và không ảnh hưởng tới biến cùng tên ở phạm
vi ngoài).
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ạm
vi 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êm
mộ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 định
nghĩ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 định
tĩ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ộc
các tên và các đối tượng. Xóa cũng vậy: câu lệnh "del x" bỏ ràng buộc x khỏi vùng tên được tham chiếu tới bởi phạm
vi nội bộ. Thực tế là mọi tác vụ có thêm các tên mới đều dùng phạm vi nội bộ: điển hình là các câu lệnh nhập và các
định nghĩa hàm buộc tên 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ột
biến cụ thể là ở phạm vi toàn cục.)
Cái nhìn đầu tiên về class
class 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 được
cho 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.
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ọi
phép gán vào các biến nội bộ đi vào vùng tên này. Đặc biệt, các định nghĩa hàm buộc tên của hàm mới ở đây.
Khi rời khỏi một định nghĩa 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ĩa
class) đượ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ác
tê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ĩa
class 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, theo
thứ 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ương
thứ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ường
hợ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ạo
trườ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)
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 được
gá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 đối
tượng. (Trong Python, từ phương thức không chỉ riêng cho trường hợp lớp: các kiểu đối tượng khác cũng có thể có
phương thức. Ví dụ, đối tượng danh sách có phương thức tên append, insert, remove, sort, v.v... Tuy nhiên, trong
phầ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ộc
tí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ông
phả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 (đối
tượ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ông
số, 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âng
mộ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ói
chung, 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ách
thô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ượng
trườ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 đó.)
Chương III 23
Một vài lời bình
Thuộc tính dữ liệu sẽ che thuộc tính phương thức cùng tên; để tránh vô tình trùng lặp tên, mà có thể dẫn đến các lỗi
rất khó tìm ra trong các chương trình lớn, bạn nên có một quy định đặt tên nào đó để giảm thiểu tỉ lệ trùng lặp. Các
quy định khả thi có thể gồm viết hoa tên phương thức, đặt tiền tố vào các tên thuộc tính dữ liệu (ví dụ như dấu gạch
dưới _), 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ách
khác, lớp không thể được dùng để cài đặt các kiểu dữ liệu trừu tượng tuyệt đối. Trong thực tế, không có gì trong
Python có thể ép việc che dấu dữ liệu, tất cả đều dựa trên nguyên tắc. (Mặt khác, cài đặt Python, được viết bằng C,
có thể dấu các chi tiết cài đặt và điểu khiển truy cập vào một đối tượng nếu cần; điều này có thể được dùng trong các
bộ mở rộng Python viết bằng C.)
Người dùng nên dùng các thuộc tính dữ liệu một cách cẩn thận, người dùng có thể phá hỏng những bất biến
(invariant) được giữ bởi các phương thức nếu cố ý sửa các thuộc tính dữ liệu. Lưu ý rằng người dùng có thể thêm các
thuộc tính dữ liệu riêng của họ vào đối tượng trường hợp mà không làm ảnh hưởng tính hợp lệ của các phương thức,
miễn là không có trùng lặp tên, xin nhắc lại, một quy tắc đặt tên có thể giảm bớt sự đau đầu ở đây.
Không có cách ngắn gọn để tham chiếu tới thuộc tính dữ liệu (hoặc các phương thức khác!) từ trong phương thức.
Điều này thật ra giúp chúng ta dễ đọc mã vì không có sự lẫn lộn giữa biến nội bộ và biến trường hợp.
Thông số đầu tiên của phương thức thường được gọi là self. Đây cũng chỉ là một quy ước: tên self hoàn toàn không
có ý 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ên
khó đọ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ủa
class đó. 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ào
mộ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ương
thứ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 đọc
cà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ục
củ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
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àm
và 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 định
nghĩ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ừa
Dĩ 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ác
biể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 module
khá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 ở trong
class, 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ếu
cầ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 khi
gọi một phương thức của cùng một đối tượng, một phương thức của class cơ sở gọi một phương thức khác được định
nghĩ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ên
củ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 theo
chiều sâu, và tìm trái qua phải. Do đó, nếu một thuộc tính không được tìm ra trong DerivedClassName, nó sẽ được
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 trong
Base2, 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ên
hơ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 hay
trong 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ính
củ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ặc
dù dễ hiểu chuyện gì xảy ra trong vấn đề này (trường hợp sẽ có một bản chép duy nhất của ``các biến trường hợp
của các thuộc tính dữ liệu dùng bởi lớp cơ sở chung), nó không rõ cho lắm nếu các ý nghĩa này thật sự hữu ích.
Biến riêng
Có 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 (textually
replace) 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áo
trộ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ủa
trườ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ông
phải lo về các biến trường hợp được định nghĩa bởi lớp con, hoặc việc sử dụng biến trường hợp bởi mã bên ngoài
lớp. Lưu ý rằng việc xáo trộn tên được thiết kế chủ yếu để tránh trùng lặp; người quyết tâm vẫn có thể truy cập
hoặc thay đổi biến riêng. Và điều này cũng có thể có ích trong các trường hợp đặc biệt, như trong trình gỡ rối, và
đó là một lý do tại sao lỗ hổng này vẫn chưa được vá.
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ày
cũ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ới
hạ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ệu
vào chung với nhau. Một định nghĩa lớp rỗng thực hiện được việc này:
class Employee:
pass
john= Employee() # Create an empty employee record
# Fill the fields of the record
john.name = 'John Doe'
john.dept = 'computer lab'
john.salary = 1000
Với mã Python cần một kiểu dữ liệu trừu tượng, ta có thể thay vào đó một lớp giả lập các phương thức của kiểu dữ
liệu đó. Ví dụ, nếu bạn có một hàm định dạng một vài dữ liệu trong một đối tượng tập tin, bạn có thể định nghĩa một
lớp với các phương thức 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ức
m, và m.im_func là đối tượng hàm tương ứng với phương thức.
Chương III 26
Biệt lệ cũng là lớp
Các biệt lệ được định nghĩa bởi người dùng cũng được định danh theo lớp. Bằng cách này, một hệ thống phân cấp
biệt lệ có thể được tạo ra. Có hai dạng lệnh raise mới: raise Class, instance
raise 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ứ hai
là 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ới
mộ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ực
thi. 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ặp
Bâ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 sau
mà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ương
thứ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:
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 ta
mộ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ếu
lớ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
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ông
thườ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 ra
rấ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ính
nă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ày
là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ạo
Một vài bộ sinh đơn giản có thể được viết một cách xúc tích như các biểu thức bằng cách dùng một cú pháp giống
như gộp danh sách (list comprehension) nhưng với ngoặc tròn thay vì ngoặc vuông. Các biểu thức này được thiết kế
cho những khi bộ sinh được sử dụng ngay lập tức bởi hàm chứa nó. Biểu thức bộ sinh gọn hơn nhưng ít khả chuyển
hơn là các định nghĩa bộ sinh đầy đủ và thường chiếm ít bộ nhớ hơn là gộp danh sách tương đương. 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']
Chương IV 29
Chương IV
Chươ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 tra
cứ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ên
chúng .
Diving In
Ví 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 đơn
giả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ương
trì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
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ơn
Ví 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 Arguments
Python 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 Functions
Python 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ày
là 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 function
Hà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)
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 Function
Ví 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:docbookdippyodbchelper.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 danh
sá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 .
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 module
chứ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 Function
type, 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.
Chương IV 33
Getting Object References with getattr
Bạ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ần
biế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ức
pop . 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 , tham
số 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ứ đối
tượ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 Modules
Ví 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
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 global
variable.
•• 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 Dispatcher
Ví 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 List
Python 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
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 or
Trong 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 trong
boolean 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.
Chương IV 36
Using the and−or Trick
Ví 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ậy
and đượ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 functions
Python 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 .
Chương IV 37
Real−World lambda Functions
Here 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 isnattest"
>>> 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 together
This 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 '
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 đó .
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ông
thường , đừng lo lắng về những vấn đề bạn không hiểu .
Vì dụ : fileinfo.py
Có 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, return
data.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])
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ần
thay đổ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=31
name=/music/_singles/a_time_long_forgotten_con.mp3 year=1999 comment=http:/ / mp3. com/ ghostmachine
album=Rave Mix artist=***DJ MARY−JANE*** title=HELLRAISER****Trance from Hell genre=31
name=/music/_singles/hellraiser.mp3 year=2000 comment=http:/ / mp3. com/ DJMARYJANE album=Rave Mix
artist=***DJ MARY−JANE*** title=KAIRO****THE BEST GOA genre=31 name=/music/_singles/kairo.mp3
year=2000
Importing Modules Using from module import
Python 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
Học python
Học python
Học python
Học python
Học python
Học python
Học python
Học python
Học python
Học python
Học python
Học python
Học python
Học python
Học python
Học python
Học python

More Related Content

What's hot

lập trình di động
lập trình di độnglập trình di động
lập trình di độngtruong le hung
 
Slide bài tập lớn ngôn ngữ lập trình - phần mềm quản lý thư viện
Slide bài tập lớn ngôn ngữ lập trình - phần mềm quản lý thư việnSlide bài tập lớn ngôn ngữ lập trình - phần mềm quản lý thư viện
Slide bài tập lớn ngôn ngữ lập trình - phần mềm quản lý thư việnThe Nguyen Manh
 
Bài giảng Công Nghệ Phần Mềm
Bài giảng Công Nghệ Phần MềmBài giảng Công Nghệ Phần Mềm
Bài giảng Công Nghệ Phần MềmHoài Phạm
 
Phân tích và thiết kế hệ thống quản lý bán hàng
Phân tích và thiết kế hệ thống quản lý bán hàngPhân tích và thiết kế hệ thống quản lý bán hàng
Phân tích và thiết kế hệ thống quản lý bán hàngleemindinh
 
Scilab for Beginners (Vietnamese)
Scilab for Beginners (Vietnamese)Scilab for Beginners (Vietnamese)
Scilab for Beginners (Vietnamese)TBSS Group
 
Đồ án kiểm thử phần mềm
Đồ án kiểm thử phần mềmĐồ án kiểm thử phần mềm
Đồ án kiểm thử phần mềmNguyễn Anh
 
Bai tap java_script-html-2016
Bai tap java_script-html-2016Bai tap java_script-html-2016
Bai tap java_script-html-2016viethoang89
 
Hướng dẫn giải bài tập chuỗi - Toán cao cấp
Hướng dẫn giải bài tập chuỗi - Toán cao cấpHướng dẫn giải bài tập chuỗi - Toán cao cấp
Hướng dẫn giải bài tập chuỗi - Toán cao cấpVan-Duyet Le
 
Bài 5: Các thuật toán sắp xếp và tìm kiếm cơ bản - Giáo trình FPT
Bài 5: Các thuật toán sắp xếp và tìm kiếm cơ bản - Giáo trình FPTBài 5: Các thuật toán sắp xếp và tìm kiếm cơ bản - Giáo trình FPT
Bài 5: Các thuật toán sắp xếp và tìm kiếm cơ bản - Giáo trình FPTMasterCode.vn
 
Slide Báo Cáo Đồ Án Tốt Nghiệp CNTT
Slide Báo Cáo Đồ Án Tốt Nghiệp CNTTSlide Báo Cáo Đồ Án Tốt Nghiệp CNTT
Slide Báo Cáo Đồ Án Tốt Nghiệp CNTTHiệu Nguyễn
 
C# Báo cáo môn lập trình hướng đối tượng - Xây dựng chương trinh quản lí sinh...
C# Báo cáo môn lập trình hướng đối tượng - Xây dựng chương trinh quản lí sinh...C# Báo cáo môn lập trình hướng đối tượng - Xây dựng chương trinh quản lí sinh...
C# Báo cáo môn lập trình hướng đối tượng - Xây dựng chương trinh quản lí sinh...Long Kingnam
 
Thuật toán Nhân Bình Phương - demo
Thuật toán Nhân Bình Phương - demoThuật toán Nhân Bình Phương - demo
Thuật toán Nhân Bình Phương - demoCông Thắng Trương
 
Ứng dụng chát realtime android
Ứng dụng chát realtime androidỨng dụng chát realtime android
Ứng dụng chát realtime androidNguyen Thieu
 
Bài tập nhập môn lập trình
Bài tập nhập môn lập trìnhBài tập nhập môn lập trình
Bài tập nhập môn lập trìnhHuy Rùa
 
Bài tập xâu cơ bản-nâng cao
Bài tập xâu cơ bản-nâng caoBài tập xâu cơ bản-nâng cao
Bài tập xâu cơ bản-nâng caoTường Tường
 
Hướng dẫn sử dụng phần mềm packet tracer
Hướng dẫn sử dụng phần mềm packet tracerHướng dẫn sử dụng phần mềm packet tracer
Hướng dẫn sử dụng phần mềm packet tracerBình Tân Phú
 
Phần 1: Các khái niệm cơ bản về lập trình
Phần 1: Các khái niệm cơ bản về lập trìnhPhần 1: Các khái niệm cơ bản về lập trình
Phần 1: Các khái niệm cơ bản về lập trìnhHuy Rùa
 

What's hot (20)

Python coban utehy
Python coban utehyPython coban utehy
Python coban utehy
 
lập trình di động
lập trình di độnglập trình di động
lập trình di động
 
Luận văn: Xây dựng ứng dụng Android nghe nhạc offline, HOT
Luận văn: Xây dựng ứng dụng Android nghe nhạc offline, HOTLuận văn: Xây dựng ứng dụng Android nghe nhạc offline, HOT
Luận văn: Xây dựng ứng dụng Android nghe nhạc offline, HOT
 
Slide bài tập lớn ngôn ngữ lập trình - phần mềm quản lý thư viện
Slide bài tập lớn ngôn ngữ lập trình - phần mềm quản lý thư việnSlide bài tập lớn ngôn ngữ lập trình - phần mềm quản lý thư viện
Slide bài tập lớn ngôn ngữ lập trình - phần mềm quản lý thư viện
 
Bài giảng Công Nghệ Phần Mềm
Bài giảng Công Nghệ Phần MềmBài giảng Công Nghệ Phần Mềm
Bài giảng Công Nghệ Phần Mềm
 
Phân tích và thiết kế hệ thống quản lý bán hàng
Phân tích và thiết kế hệ thống quản lý bán hàngPhân tích và thiết kế hệ thống quản lý bán hàng
Phân tích và thiết kế hệ thống quản lý bán hàng
 
Scilab for Beginners (Vietnamese)
Scilab for Beginners (Vietnamese)Scilab for Beginners (Vietnamese)
Scilab for Beginners (Vietnamese)
 
Đồ án kiểm thử phần mềm
Đồ án kiểm thử phần mềmĐồ án kiểm thử phần mềm
Đồ án kiểm thử phần mềm
 
Bai tap java_script-html-2016
Bai tap java_script-html-2016Bai tap java_script-html-2016
Bai tap java_script-html-2016
 
Hướng dẫn giải bài tập chuỗi - Toán cao cấp
Hướng dẫn giải bài tập chuỗi - Toán cao cấpHướng dẫn giải bài tập chuỗi - Toán cao cấp
Hướng dẫn giải bài tập chuỗi - Toán cao cấp
 
Đề tài: Xây dựng Web bán và giới thiệu văn phòng phẩm, HAY
Đề tài: Xây dựng Web bán và giới thiệu văn phòng phẩm, HAYĐề tài: Xây dựng Web bán và giới thiệu văn phòng phẩm, HAY
Đề tài: Xây dựng Web bán và giới thiệu văn phòng phẩm, HAY
 
Bài 5: Các thuật toán sắp xếp và tìm kiếm cơ bản - Giáo trình FPT
Bài 5: Các thuật toán sắp xếp và tìm kiếm cơ bản - Giáo trình FPTBài 5: Các thuật toán sắp xếp và tìm kiếm cơ bản - Giáo trình FPT
Bài 5: Các thuật toán sắp xếp và tìm kiếm cơ bản - Giáo trình FPT
 
Slide Báo Cáo Đồ Án Tốt Nghiệp CNTT
Slide Báo Cáo Đồ Án Tốt Nghiệp CNTTSlide Báo Cáo Đồ Án Tốt Nghiệp CNTT
Slide Báo Cáo Đồ Án Tốt Nghiệp CNTT
 
C# Báo cáo môn lập trình hướng đối tượng - Xây dựng chương trinh quản lí sinh...
C# Báo cáo môn lập trình hướng đối tượng - Xây dựng chương trinh quản lí sinh...C# Báo cáo môn lập trình hướng đối tượng - Xây dựng chương trinh quản lí sinh...
C# Báo cáo môn lập trình hướng đối tượng - Xây dựng chương trinh quản lí sinh...
 
Thuật toán Nhân Bình Phương - demo
Thuật toán Nhân Bình Phương - demoThuật toán Nhân Bình Phương - demo
Thuật toán Nhân Bình Phương - demo
 
Ứng dụng chát realtime android
Ứng dụng chát realtime androidỨng dụng chát realtime android
Ứng dụng chát realtime android
 
Bài tập nhập môn lập trình
Bài tập nhập môn lập trìnhBài tập nhập môn lập trình
Bài tập nhập môn lập trình
 
Bài tập xâu cơ bản-nâng cao
Bài tập xâu cơ bản-nâng caoBài tập xâu cơ bản-nâng cao
Bài tập xâu cơ bản-nâng cao
 
Hướng dẫn sử dụng phần mềm packet tracer
Hướng dẫn sử dụng phần mềm packet tracerHướng dẫn sử dụng phần mềm packet tracer
Hướng dẫn sử dụng phần mềm packet tracer
 
Phần 1: Các khái niệm cơ bản về lập trình
Phần 1: Các khái niệm cơ bản về lập trìnhPhần 1: Các khái niệm cơ bản về lập trình
Phần 1: Các khái niệm cơ bản về lập trình
 

Similar to Học python

Tu-Hoc-Python-Co-Ban-Trong-10-Phut-NIIT
Tu-Hoc-Python-Co-Ban-Trong-10-Phut-NIITTu-Hoc-Python-Co-Ban-Trong-10-Phut-NIIT
Tu-Hoc-Python-Co-Ban-Trong-10-Phut-NIITNIIT - ICT Hà Nội
 
Hướng dẫn deobfuscate DotnetPatcher 3.1 - Bài dịch
Hướng dẫn deobfuscate DotnetPatcher 3.1 - Bài dịchHướng dẫn deobfuscate DotnetPatcher 3.1 - Bài dịch
Hướng dẫn deobfuscate DotnetPatcher 3.1 - Bài dịchLevis Nickaster
 
ngon-ngu-lap-trinh-python_C1_cac_khai_niem_(PII).pptx
ngon-ngu-lap-trinh-python_C1_cac_khai_niem_(PII).pptxngon-ngu-lap-trinh-python_C1_cac_khai_niem_(PII).pptx
ngon-ngu-lap-trinh-python_C1_cac_khai_niem_(PII).pptxssuser49db3c1
 
Phân tích Confuser 1.9.0.0 - Constant Protection - Bản dịch
Phân tích Confuser 1.9.0.0 - Constant Protection - Bản dịchPhân tích Confuser 1.9.0.0 - Constant Protection - Bản dịch
Phân tích Confuser 1.9.0.0 - Constant Protection - Bản dịchLevis Nickaster
 
Bài tập về chuẩn hóa chuỗ1
Bài tập về chuẩn hóa chuỗ1Bài tập về chuẩn hóa chuỗ1
Bài tập về chuẩn hóa chuỗ1Nguyen Van Hung
 
Ngon ngu c theo chuan ansi
Ngon ngu c theo chuan ansiNgon ngu c theo chuan ansi
Ngon ngu c theo chuan ansiHuynh MVT
 
Phân tích Confuser 1.9.0.0 - Anti-tamper protection - Bản dịch
Phân tích Confuser 1.9.0.0 - Anti-tamper protection - Bản dịchPhân tích Confuser 1.9.0.0 - Anti-tamper protection - Bản dịch
Phân tích Confuser 1.9.0.0 - Anti-tamper protection - Bản dịchLevis Nickaster
 
Lập trình C cho VĐK 8051
Lập trình C cho VĐK 8051Lập trình C cho VĐK 8051
Lập trình C cho VĐK 8051Mr Giap
 
Stl vector nguyen_trihai_11520094_khmt06
Stl vector nguyen_trihai_11520094_khmt06Stl vector nguyen_trihai_11520094_khmt06
Stl vector nguyen_trihai_11520094_khmt06Quach Long
 
OOP_02_Java can ban.pdf
OOP_02_Java can ban.pdfOOP_02_Java can ban.pdf
OOP_02_Java can ban.pdfssuserd01a5c
 
Phong cach lap trinh c++
Phong cach lap trinh c++Phong cach lap trinh c++
Phong cach lap trinh c++ptquang160492
 
C++ can ban(dung thu vien iostream)
C++ can ban(dung thu vien iostream)C++ can ban(dung thu vien iostream)
C++ can ban(dung thu vien iostream)Nguyễn Phụng
 
Decrypt các MSIL methods một cách thử công - Bài dịch
Decrypt các MSIL methods một cách thử công - Bài dịchDecrypt các MSIL methods một cách thử công - Bài dịch
Decrypt các MSIL methods một cách thử công - Bài dịchLevis Nickaster
 
Slide Python Bai 2 pythonvietnam.info
Slide Python Bai 2   pythonvietnam.infoSlide Python Bai 2   pythonvietnam.info
Slide Python Bai 2 pythonvietnam.infoKhánh Nguyễn
 
Hacking de4dot for fun - Bài dịch
Hacking de4dot for fun - Bài dịchHacking de4dot for fun - Bài dịch
Hacking de4dot for fun - Bài dịchLevis Nickaster
 

Similar to Học python (20)

Tu-Hoc-Python-Co-Ban-Trong-10-Phut-NIIT
Tu-Hoc-Python-Co-Ban-Trong-10-Phut-NIITTu-Hoc-Python-Co-Ban-Trong-10-Phut-NIIT
Tu-Hoc-Python-Co-Ban-Trong-10-Phut-NIIT
 
temp.pdf
temp.pdftemp.pdf
temp.pdf
 
Hướng dẫn deobfuscate DotnetPatcher 3.1 - Bài dịch
Hướng dẫn deobfuscate DotnetPatcher 3.1 - Bài dịchHướng dẫn deobfuscate DotnetPatcher 3.1 - Bài dịch
Hướng dẫn deobfuscate DotnetPatcher 3.1 - Bài dịch
 
C++ can ban
C++ can banC++ can ban
C++ can ban
 
ngon-ngu-lap-trinh-python_C1_cac_khai_niem_(PII).pptx
ngon-ngu-lap-trinh-python_C1_cac_khai_niem_(PII).pptxngon-ngu-lap-trinh-python_C1_cac_khai_niem_(PII).pptx
ngon-ngu-lap-trinh-python_C1_cac_khai_niem_(PII).pptx
 
Phân tích Confuser 1.9.0.0 - Constant Protection - Bản dịch
Phân tích Confuser 1.9.0.0 - Constant Protection - Bản dịchPhân tích Confuser 1.9.0.0 - Constant Protection - Bản dịch
Phân tích Confuser 1.9.0.0 - Constant Protection - Bản dịch
 
Lect09 string
Lect09 stringLect09 string
Lect09 string
 
Bài tập về chuẩn hóa chuỗ1
Bài tập về chuẩn hóa chuỗ1Bài tập về chuẩn hóa chuỗ1
Bài tập về chuẩn hóa chuỗ1
 
Ngon ngu c theo chuan ansi
Ngon ngu c theo chuan ansiNgon ngu c theo chuan ansi
Ngon ngu c theo chuan ansi
 
Phân tích Confuser 1.9.0.0 - Anti-tamper protection - Bản dịch
Phân tích Confuser 1.9.0.0 - Anti-tamper protection - Bản dịchPhân tích Confuser 1.9.0.0 - Anti-tamper protection - Bản dịch
Phân tích Confuser 1.9.0.0 - Anti-tamper protection - Bản dịch
 
String c++
String c++String c++
String c++
 
Lập trình C cho VĐK 8051
Lập trình C cho VĐK 8051Lập trình C cho VĐK 8051
Lập trình C cho VĐK 8051
 
Stl vector nguyen_trihai_11520094_khmt06
Stl vector nguyen_trihai_11520094_khmt06Stl vector nguyen_trihai_11520094_khmt06
Stl vector nguyen_trihai_11520094_khmt06
 
OOP_02_Java can ban.pdf
OOP_02_Java can ban.pdfOOP_02_Java can ban.pdf
OOP_02_Java can ban.pdf
 
Phong cach lap trinh c++
Phong cach lap trinh c++Phong cach lap trinh c++
Phong cach lap trinh c++
 
Phong cach lap trinh c++
Phong cach lap trinh c++Phong cach lap trinh c++
Phong cach lap trinh c++
 
C++ can ban(dung thu vien iostream)
C++ can ban(dung thu vien iostream)C++ can ban(dung thu vien iostream)
C++ can ban(dung thu vien iostream)
 
Decrypt các MSIL methods một cách thử công - Bài dịch
Decrypt các MSIL methods một cách thử công - Bài dịchDecrypt các MSIL methods một cách thử công - Bài dịch
Decrypt các MSIL methods một cách thử công - Bài dịch
 
Slide Python Bai 2 pythonvietnam.info
Slide Python Bai 2   pythonvietnam.infoSlide Python Bai 2   pythonvietnam.info
Slide Python Bai 2 pythonvietnam.info
 
Hacking de4dot for fun - Bài dịch
Hacking de4dot for fun - Bài dịchHacking de4dot for fun - Bài dịch
Hacking de4dot for fun - Bài dịch
 

More from Tung Nguyen Xuan

Giáo Trình thí nghiệm và kiểm định công trình
Giáo Trình thí nghiệm và kiểm định công trìnhGiáo Trình thí nghiệm và kiểm định công trình
Giáo Trình thí nghiệm và kiểm định công trìnhTung Nguyen Xuan
 
Bài giảng thí nghiệm và kiểm định công trình- TS.Nguyễn Trung Hiếu
Bài giảng thí nghiệm và kiểm định công trình- TS.Nguyễn Trung HiếuBài giảng thí nghiệm và kiểm định công trình- TS.Nguyễn Trung Hiếu
Bài giảng thí nghiệm và kiểm định công trình- TS.Nguyễn Trung HiếuTung Nguyen Xuan
 
Bản vẽ Đồ án kỹ thuật thi công 2
Bản vẽ Đồ án kỹ thuật thi công 2Bản vẽ Đồ án kỹ thuật thi công 2
Bản vẽ Đồ án kỹ thuật thi công 2Tung Nguyen Xuan
 
Thiết kế biện pháp kĩ thuật thi công lắp ghép nhà công nghiệp 1 tầng
Thiết kế biện pháp kĩ thuật thi công lắp ghép nhà công nghiệp 1 tầngThiết kế biện pháp kĩ thuật thi công lắp ghép nhà công nghiệp 1 tầng
Thiết kế biện pháp kĩ thuật thi công lắp ghép nhà công nghiệp 1 tầngTung Nguyen Xuan
 
Hướng dẫn đồ án kỹ thuật thi công- Thầy Doãn Hiệu
Hướng dẫn đồ án kỹ thuật thi công- Thầy Doãn HiệuHướng dẫn đồ án kỹ thuật thi công- Thầy Doãn Hiệu
Hướng dẫn đồ án kỹ thuật thi công- Thầy Doãn HiệuTung Nguyen Xuan
 
Thuyết minh hướng dẫn đồ án kỹ thuật thi công 1
Thuyết minh hướng dẫn đồ án kỹ thuật thi công 1Thuyết minh hướng dẫn đồ án kỹ thuật thi công 1
Thuyết minh hướng dẫn đồ án kỹ thuật thi công 1Tung Nguyen Xuan
 
Bản vẽ đồ án Nền móng- Đại học Xây dựng
Bản vẽ đồ án Nền móng- Đại học Xây dựngBản vẽ đồ án Nền móng- Đại học Xây dựng
Bản vẽ đồ án Nền móng- Đại học Xây dựngTung Nguyen Xuan
 
Hướng dẫn-Thuyết minh Đồ án kết cấu thép nhà công nghiệp
Hướng dẫn-Thuyết minh Đồ án kết cấu thép nhà công nghiệpHướng dẫn-Thuyết minh Đồ án kết cấu thép nhà công nghiệp
Hướng dẫn-Thuyết minh Đồ án kết cấu thép nhà công nghiệpTung Nguyen Xuan
 
Sàn sườn bê tông cốt thép toàn khối- Đại Học Xây Dựng
Sàn sườn bê tông cốt thép toàn khối- Đại Học Xây DựngSàn sườn bê tông cốt thép toàn khối- Đại Học Xây Dựng
Sàn sườn bê tông cốt thép toàn khối- Đại Học Xây DựngTung Nguyen Xuan
 
Động lực học công trình
Động lực học công trìnhĐộng lực học công trình
Động lực học công trìnhTung Nguyen Xuan
 

More from Tung Nguyen Xuan (13)

Giáo Trình thí nghiệm và kiểm định công trình
Giáo Trình thí nghiệm và kiểm định công trìnhGiáo Trình thí nghiệm và kiểm định công trình
Giáo Trình thí nghiệm và kiểm định công trình
 
Bài giảng thí nghiệm và kiểm định công trình- TS.Nguyễn Trung Hiếu
Bài giảng thí nghiệm và kiểm định công trình- TS.Nguyễn Trung HiếuBài giảng thí nghiệm và kiểm định công trình- TS.Nguyễn Trung Hiếu
Bài giảng thí nghiệm và kiểm định công trình- TS.Nguyễn Trung Hiếu
 
Bản vẽ Đồ án kỹ thuật thi công 2
Bản vẽ Đồ án kỹ thuật thi công 2Bản vẽ Đồ án kỹ thuật thi công 2
Bản vẽ Đồ án kỹ thuật thi công 2
 
Thiết kế biện pháp kĩ thuật thi công lắp ghép nhà công nghiệp 1 tầng
Thiết kế biện pháp kĩ thuật thi công lắp ghép nhà công nghiệp 1 tầngThiết kế biện pháp kĩ thuật thi công lắp ghép nhà công nghiệp 1 tầng
Thiết kế biện pháp kĩ thuật thi công lắp ghép nhà công nghiệp 1 tầng
 
Hướng dẫn đồ án kỹ thuật thi công- Thầy Doãn Hiệu
Hướng dẫn đồ án kỹ thuật thi công- Thầy Doãn HiệuHướng dẫn đồ án kỹ thuật thi công- Thầy Doãn Hiệu
Hướng dẫn đồ án kỹ thuật thi công- Thầy Doãn Hiệu
 
Thuyết minh hướng dẫn đồ án kỹ thuật thi công 1
Thuyết minh hướng dẫn đồ án kỹ thuật thi công 1Thuyết minh hướng dẫn đồ án kỹ thuật thi công 1
Thuyết minh hướng dẫn đồ án kỹ thuật thi công 1
 
Bản vẽ đồ án Nền móng- Đại học Xây dựng
Bản vẽ đồ án Nền móng- Đại học Xây dựngBản vẽ đồ án Nền móng- Đại học Xây dựng
Bản vẽ đồ án Nền móng- Đại học Xây dựng
 
Hướng dẫn-Thuyết minh Đồ án kết cấu thép nhà công nghiệp
Hướng dẫn-Thuyết minh Đồ án kết cấu thép nhà công nghiệpHướng dẫn-Thuyết minh Đồ án kết cấu thép nhà công nghiệp
Hướng dẫn-Thuyết minh Đồ án kết cấu thép nhà công nghiệp
 
Cong nghe be tong xi mang
Cong nghe be tong xi mangCong nghe be tong xi mang
Cong nghe be tong xi mang
 
Cơ học đất- whitlow
Cơ học đất- whitlowCơ học đất- whitlow
Cơ học đất- whitlow
 
Sàn sườn bê tông cốt thép toàn khối- Đại Học Xây Dựng
Sàn sườn bê tông cốt thép toàn khối- Đại Học Xây DựngSàn sườn bê tông cốt thép toàn khối- Đại Học Xây Dựng
Sàn sườn bê tông cốt thép toàn khối- Đại Học Xây Dựng
 
Động lực học công trình
Động lực học công trìnhĐộng lực học công trình
Động lực học công trình
 
Giáo trình sketch up
Giáo trình sketch upGiáo trình sketch up
Giáo trình sketch up
 

Recently uploaded

Slide Webinar Hướng dẫn sử dụng ChatGPT cho người mới bắt đầ...
Slide Webinar Hướng dẫn sử dụng ChatGPT cho người mới bắt đầ...Slide Webinar Hướng dẫn sử dụng ChatGPT cho người mới bắt đầ...
Slide Webinar Hướng dẫn sử dụng ChatGPT cho người mới bắt đầ...Học viện Kstudy
 
BỘ ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
BỘ ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...BỘ ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
BỘ ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...Nguyen Thanh Tu Collection
 
ôn tập lịch sử hhhhhhhhhhhhhhhhhhhhhhhhhh
ôn tập lịch sử hhhhhhhhhhhhhhhhhhhhhhhhhhôn tập lịch sử hhhhhhhhhhhhhhhhhhhhhhhhhh
ôn tập lịch sử hhhhhhhhhhhhhhhhhhhhhhhhhhvanhathvc
 
Hệ phương trình tuyến tính và các ứng dụng trong kinh tế
Hệ phương trình tuyến tính và các ứng dụng trong kinh tếHệ phương trình tuyến tính và các ứng dụng trong kinh tế
Hệ phương trình tuyến tính và các ứng dụng trong kinh tếngTonH1
 
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...Nguyen Thanh Tu Collection
 
Chàm - Bệnh án (da liễu - bvdlct ctump) .pptx
Chàm - Bệnh án (da liễu - bvdlct ctump) .pptxChàm - Bệnh án (da liễu - bvdlct ctump) .pptx
Chàm - Bệnh án (da liễu - bvdlct ctump) .pptxendkay31
 
Kiểm tra chạy trạm lí thuyết giữa kì giải phẫu sinh lí
Kiểm tra chạy trạm lí thuyết giữa kì giải phẫu sinh líKiểm tra chạy trạm lí thuyết giữa kì giải phẫu sinh lí
Kiểm tra chạy trạm lí thuyết giữa kì giải phẫu sinh líDr K-OGN
 
QUẢN LÝ HOẠT ĐỘNG GIÁO DỤC KỸ NĂNG SỐNG CHO HỌC SINH CÁC TRƯỜNG TRUNG HỌC CƠ ...
QUẢN LÝ HOẠT ĐỘNG GIÁO DỤC KỸ NĂNG SỐNG CHO HỌC SINH CÁC TRƯỜNG TRUNG HỌC CƠ ...QUẢN LÝ HOẠT ĐỘNG GIÁO DỤC KỸ NĂNG SỐNG CHO HỌC SINH CÁC TRƯỜNG TRUNG HỌC CƠ ...
QUẢN LÝ HOẠT ĐỘNG GIÁO DỤC KỸ NĂNG SỐNG CHO HỌC SINH CÁC TRƯỜNG TRUNG HỌC CƠ ...ThunTrn734461
 
Thong bao 337-DHPY (24.4.2024) thi sat hach Ngoai ngu dap ung Chuan dau ra do...
Thong bao 337-DHPY (24.4.2024) thi sat hach Ngoai ngu dap ung Chuan dau ra do...Thong bao 337-DHPY (24.4.2024) thi sat hach Ngoai ngu dap ung Chuan dau ra do...
Thong bao 337-DHPY (24.4.2024) thi sat hach Ngoai ngu dap ung Chuan dau ra do...hoangtuansinh1
 
10 ĐỀ KIỂM TRA + 6 ĐỀ ÔN TẬP CUỐI KÌ 2 VẬT LÝ 11 - KẾT NỐI TRI THỨC - THEO C...
10 ĐỀ KIỂM TRA + 6 ĐỀ ÔN TẬP CUỐI KÌ 2 VẬT LÝ 11 - KẾT NỐI TRI THỨC - THEO C...10 ĐỀ KIỂM TRA + 6 ĐỀ ÔN TẬP CUỐI KÌ 2 VẬT LÝ 11 - KẾT NỐI TRI THỨC - THEO C...
10 ĐỀ KIỂM TRA + 6 ĐỀ ÔN TẬP CUỐI KÌ 2 VẬT LÝ 11 - KẾT NỐI TRI THỨC - THEO C...Nguyen Thanh Tu Collection
 
TỔNG HỢP ĐỀ THI CHÍNH THỨC KỲ THI TUYỂN SINH VÀO LỚP 10 THPT MÔN NGỮ VĂN NĂM ...
TỔNG HỢP ĐỀ THI CHÍNH THỨC KỲ THI TUYỂN SINH VÀO LỚP 10 THPT MÔN NGỮ VĂN NĂM ...TỔNG HỢP ĐỀ THI CHÍNH THỨC KỲ THI TUYỂN SINH VÀO LỚP 10 THPT MÔN NGỮ VĂN NĂM ...
TỔNG HỢP ĐỀ THI CHÍNH THỨC KỲ THI TUYỂN SINH VÀO LỚP 10 THPT MÔN NGỮ VĂN NĂM ...Nguyen Thanh Tu Collection
 
bài 5.1.docx Sinh học di truyền đại cương năm nhất của học sinh y đa khoa
bài 5.1.docx Sinh học di truyền đại cương năm nhất của học sinh y đa khoabài 5.1.docx Sinh học di truyền đại cương năm nhất của học sinh y đa khoa
bài 5.1.docx Sinh học di truyền đại cương năm nhất của học sinh y đa khoa2353020138
 
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...Nguyen Thanh Tu Collection
 
ĐỀ THAM KHẢO THEO HƯỚNG MINH HỌA 2025 KIỂM TRA CUỐI HỌC KÌ 2 NĂM HỌC 2023-202...
ĐỀ THAM KHẢO THEO HƯỚNG MINH HỌA 2025 KIỂM TRA CUỐI HỌC KÌ 2 NĂM HỌC 2023-202...ĐỀ THAM KHẢO THEO HƯỚNG MINH HỌA 2025 KIỂM TRA CUỐI HỌC KÌ 2 NĂM HỌC 2023-202...
ĐỀ THAM KHẢO THEO HƯỚNG MINH HỌA 2025 KIỂM TRA CUỐI HỌC KÌ 2 NĂM HỌC 2023-202...Nguyen Thanh Tu Collection
 
SÁNG KIẾN “THIẾT KẾ VÀ SỬ DỤNG INFOGRAPHIC TRONG DẠY HỌC ĐỊA LÍ 11 (BỘ SÁCH K...
SÁNG KIẾN “THIẾT KẾ VÀ SỬ DỤNG INFOGRAPHIC TRONG DẠY HỌC ĐỊA LÍ 11 (BỘ SÁCH K...SÁNG KIẾN “THIẾT KẾ VÀ SỬ DỤNG INFOGRAPHIC TRONG DẠY HỌC ĐỊA LÍ 11 (BỘ SÁCH K...
SÁNG KIẾN “THIẾT KẾ VÀ SỬ DỤNG INFOGRAPHIC TRONG DẠY HỌC ĐỊA LÍ 11 (BỘ SÁCH K...Nguyen Thanh Tu Collection
 
Bai 1 cong bo mot cong trinh nghien cuu khoa hoc
Bai 1 cong bo mot cong trinh nghien cuu khoa hocBai 1 cong bo mot cong trinh nghien cuu khoa hoc
Bai 1 cong bo mot cong trinh nghien cuu khoa hocVnPhan58
 
Sáng kiến Dạy học theo định hướng STEM một số chủ đề phần “vật sống”, Khoa họ...
Sáng kiến Dạy học theo định hướng STEM một số chủ đề phần “vật sống”, Khoa họ...Sáng kiến Dạy học theo định hướng STEM một số chủ đề phần “vật sống”, Khoa họ...
Sáng kiến Dạy học theo định hướng STEM một số chủ đề phần “vật sống”, Khoa họ...Nguyen Thanh Tu Collection
 
Chuong trinh dao tao Su pham Khoa hoc tu nhien, ma nganh - 7140247.pdf
Chuong trinh dao tao Su pham Khoa hoc tu nhien, ma nganh - 7140247.pdfChuong trinh dao tao Su pham Khoa hoc tu nhien, ma nganh - 7140247.pdf
Chuong trinh dao tao Su pham Khoa hoc tu nhien, ma nganh - 7140247.pdfhoangtuansinh1
 
BỘ ĐỀ KIỂM TRA CUỐI KÌ 2 VẬT LÝ 11 - KẾT NỐI TRI THỨC - THEO CẤU TRÚC ĐỀ MIN...
BỘ ĐỀ KIỂM TRA CUỐI KÌ 2 VẬT LÝ 11 - KẾT NỐI TRI THỨC - THEO CẤU TRÚC ĐỀ MIN...BỘ ĐỀ KIỂM TRA CUỐI KÌ 2 VẬT LÝ 11 - KẾT NỐI TRI THỨC - THEO CẤU TRÚC ĐỀ MIN...
BỘ ĐỀ KIỂM TRA CUỐI KÌ 2 VẬT LÝ 11 - KẾT NỐI TRI THỨC - THEO CẤU TRÚC ĐỀ MIN...Nguyen Thanh Tu Collection
 
Sáng kiến “Sử dụng ứng dụng Quizizz nhằm nâng cao chất lượng ôn thi tốt nghiệ...
Sáng kiến “Sử dụng ứng dụng Quizizz nhằm nâng cao chất lượng ôn thi tốt nghiệ...Sáng kiến “Sử dụng ứng dụng Quizizz nhằm nâng cao chất lượng ôn thi tốt nghiệ...
Sáng kiến “Sử dụng ứng dụng Quizizz nhằm nâng cao chất lượng ôn thi tốt nghiệ...Nguyen Thanh Tu Collection
 

Recently uploaded (20)

Slide Webinar Hướng dẫn sử dụng ChatGPT cho người mới bắt đầ...
Slide Webinar Hướng dẫn sử dụng ChatGPT cho người mới bắt đầ...Slide Webinar Hướng dẫn sử dụng ChatGPT cho người mới bắt đầ...
Slide Webinar Hướng dẫn sử dụng ChatGPT cho người mới bắt đầ...
 
BỘ ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
BỘ ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...BỘ ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
BỘ ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
 
ôn tập lịch sử hhhhhhhhhhhhhhhhhhhhhhhhhh
ôn tập lịch sử hhhhhhhhhhhhhhhhhhhhhhhhhhôn tập lịch sử hhhhhhhhhhhhhhhhhhhhhhhhhh
ôn tập lịch sử hhhhhhhhhhhhhhhhhhhhhhhhhh
 
Hệ phương trình tuyến tính và các ứng dụng trong kinh tế
Hệ phương trình tuyến tính và các ứng dụng trong kinh tếHệ phương trình tuyến tính và các ứng dụng trong kinh tế
Hệ phương trình tuyến tính và các ứng dụng trong kinh tế
 
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
 
Chàm - Bệnh án (da liễu - bvdlct ctump) .pptx
Chàm - Bệnh án (da liễu - bvdlct ctump) .pptxChàm - Bệnh án (da liễu - bvdlct ctump) .pptx
Chàm - Bệnh án (da liễu - bvdlct ctump) .pptx
 
Kiểm tra chạy trạm lí thuyết giữa kì giải phẫu sinh lí
Kiểm tra chạy trạm lí thuyết giữa kì giải phẫu sinh líKiểm tra chạy trạm lí thuyết giữa kì giải phẫu sinh lí
Kiểm tra chạy trạm lí thuyết giữa kì giải phẫu sinh lí
 
QUẢN LÝ HOẠT ĐỘNG GIÁO DỤC KỸ NĂNG SỐNG CHO HỌC SINH CÁC TRƯỜNG TRUNG HỌC CƠ ...
QUẢN LÝ HOẠT ĐỘNG GIÁO DỤC KỸ NĂNG SỐNG CHO HỌC SINH CÁC TRƯỜNG TRUNG HỌC CƠ ...QUẢN LÝ HOẠT ĐỘNG GIÁO DỤC KỸ NĂNG SỐNG CHO HỌC SINH CÁC TRƯỜNG TRUNG HỌC CƠ ...
QUẢN LÝ HOẠT ĐỘNG GIÁO DỤC KỸ NĂNG SỐNG CHO HỌC SINH CÁC TRƯỜNG TRUNG HỌC CƠ ...
 
Thong bao 337-DHPY (24.4.2024) thi sat hach Ngoai ngu dap ung Chuan dau ra do...
Thong bao 337-DHPY (24.4.2024) thi sat hach Ngoai ngu dap ung Chuan dau ra do...Thong bao 337-DHPY (24.4.2024) thi sat hach Ngoai ngu dap ung Chuan dau ra do...
Thong bao 337-DHPY (24.4.2024) thi sat hach Ngoai ngu dap ung Chuan dau ra do...
 
10 ĐỀ KIỂM TRA + 6 ĐỀ ÔN TẬP CUỐI KÌ 2 VẬT LÝ 11 - KẾT NỐI TRI THỨC - THEO C...
10 ĐỀ KIỂM TRA + 6 ĐỀ ÔN TẬP CUỐI KÌ 2 VẬT LÝ 11 - KẾT NỐI TRI THỨC - THEO C...10 ĐỀ KIỂM TRA + 6 ĐỀ ÔN TẬP CUỐI KÌ 2 VẬT LÝ 11 - KẾT NỐI TRI THỨC - THEO C...
10 ĐỀ KIỂM TRA + 6 ĐỀ ÔN TẬP CUỐI KÌ 2 VẬT LÝ 11 - KẾT NỐI TRI THỨC - THEO C...
 
TỔNG HỢP ĐỀ THI CHÍNH THỨC KỲ THI TUYỂN SINH VÀO LỚP 10 THPT MÔN NGỮ VĂN NĂM ...
TỔNG HỢP ĐỀ THI CHÍNH THỨC KỲ THI TUYỂN SINH VÀO LỚP 10 THPT MÔN NGỮ VĂN NĂM ...TỔNG HỢP ĐỀ THI CHÍNH THỨC KỲ THI TUYỂN SINH VÀO LỚP 10 THPT MÔN NGỮ VĂN NĂM ...
TỔNG HỢP ĐỀ THI CHÍNH THỨC KỲ THI TUYỂN SINH VÀO LỚP 10 THPT MÔN NGỮ VĂN NĂM ...
 
bài 5.1.docx Sinh học di truyền đại cương năm nhất của học sinh y đa khoa
bài 5.1.docx Sinh học di truyền đại cương năm nhất của học sinh y đa khoabài 5.1.docx Sinh học di truyền đại cương năm nhất của học sinh y đa khoa
bài 5.1.docx Sinh học di truyền đại cương năm nhất của học sinh y đa khoa
 
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
 
ĐỀ THAM KHẢO THEO HƯỚNG MINH HỌA 2025 KIỂM TRA CUỐI HỌC KÌ 2 NĂM HỌC 2023-202...
ĐỀ THAM KHẢO THEO HƯỚNG MINH HỌA 2025 KIỂM TRA CUỐI HỌC KÌ 2 NĂM HỌC 2023-202...ĐỀ THAM KHẢO THEO HƯỚNG MINH HỌA 2025 KIỂM TRA CUỐI HỌC KÌ 2 NĂM HỌC 2023-202...
ĐỀ THAM KHẢO THEO HƯỚNG MINH HỌA 2025 KIỂM TRA CUỐI HỌC KÌ 2 NĂM HỌC 2023-202...
 
SÁNG KIẾN “THIẾT KẾ VÀ SỬ DỤNG INFOGRAPHIC TRONG DẠY HỌC ĐỊA LÍ 11 (BỘ SÁCH K...
SÁNG KIẾN “THIẾT KẾ VÀ SỬ DỤNG INFOGRAPHIC TRONG DẠY HỌC ĐỊA LÍ 11 (BỘ SÁCH K...SÁNG KIẾN “THIẾT KẾ VÀ SỬ DỤNG INFOGRAPHIC TRONG DẠY HỌC ĐỊA LÍ 11 (BỘ SÁCH K...
SÁNG KIẾN “THIẾT KẾ VÀ SỬ DỤNG INFOGRAPHIC TRONG DẠY HỌC ĐỊA LÍ 11 (BỘ SÁCH K...
 
Bai 1 cong bo mot cong trinh nghien cuu khoa hoc
Bai 1 cong bo mot cong trinh nghien cuu khoa hocBai 1 cong bo mot cong trinh nghien cuu khoa hoc
Bai 1 cong bo mot cong trinh nghien cuu khoa hoc
 
Sáng kiến Dạy học theo định hướng STEM một số chủ đề phần “vật sống”, Khoa họ...
Sáng kiến Dạy học theo định hướng STEM một số chủ đề phần “vật sống”, Khoa họ...Sáng kiến Dạy học theo định hướng STEM một số chủ đề phần “vật sống”, Khoa họ...
Sáng kiến Dạy học theo định hướng STEM một số chủ đề phần “vật sống”, Khoa họ...
 
Chuong trinh dao tao Su pham Khoa hoc tu nhien, ma nganh - 7140247.pdf
Chuong trinh dao tao Su pham Khoa hoc tu nhien, ma nganh - 7140247.pdfChuong trinh dao tao Su pham Khoa hoc tu nhien, ma nganh - 7140247.pdf
Chuong trinh dao tao Su pham Khoa hoc tu nhien, ma nganh - 7140247.pdf
 
BỘ ĐỀ KIỂM TRA CUỐI KÌ 2 VẬT LÝ 11 - KẾT NỐI TRI THỨC - THEO CẤU TRÚC ĐỀ MIN...
BỘ ĐỀ KIỂM TRA CUỐI KÌ 2 VẬT LÝ 11 - KẾT NỐI TRI THỨC - THEO CẤU TRÚC ĐỀ MIN...BỘ ĐỀ KIỂM TRA CUỐI KÌ 2 VẬT LÝ 11 - KẾT NỐI TRI THỨC - THEO CẤU TRÚC ĐỀ MIN...
BỘ ĐỀ KIỂM TRA CUỐI KÌ 2 VẬT LÝ 11 - KẾT NỐI TRI THỨC - THEO CẤU TRÚC ĐỀ MIN...
 
Sáng kiến “Sử dụng ứng dụng Quizizz nhằm nâng cao chất lượng ôn thi tốt nghiệ...
Sáng kiến “Sử dụng ứng dụng Quizizz nhằm nâng cao chất lượng ôn thi tốt nghiệ...Sáng kiến “Sử dụng ứng dụng Quizizz nhằm nâng cao chất lượng ôn thi tốt nghiệ...
Sáng kiến “Sử dụng ứng dụng Quizizz nhằm nâng cao chất lượng ôn thi tốt nghiệ...
 

Học python

  • 1. 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
  • 2. Nội dung Bài Chương I 1 Chương II 14 Chương III 17 Chương IV 29 Chương V 39 Bài tập căn bản 48 Chú thích Nguồn và người đóng góp vào bài 55 Nguồn, giấy phép, và người đóng góp vào hình 56 Giấy phép Bài viết Giấy phép 57
  • 3. 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ọn version 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.c gcc −pthread −c −fno−strict−aliasing −DNDEBUG −g −O3 −Wall −Wstrict−prototypes −I. −I./Include −DPy_BUILD_CORE −o Parser/acceler.o Parser/acceler.c gcc −pthread −c −fno−strict−aliasing −DNDEBUG −g −O3 −Wall −Wstrict−prototypes
  • 4. 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ổ Shell Bâ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ôi cò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.
  • 5. Chương I 3 Viết Python Bằng Eclipse Eclipse 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:
  • 6. 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
  • 8. 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:
  • 9. 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 :
  • 10. Chương I 8 Chuỗi Ngoài số, Python còn làm việc được với chuỗi, có thể được biểu hiện theo nhiều cách. Chúng có thể được kẹp trong dấu nháy đơn, đôi: >>> '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ột dấu suỵt huyền là ký tự cuối cùng trên một dòng cho biết rằng dòng kế là sự nối tiếp của dòng này: hello = "This is a rather long string containingn 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.
  • 11. Chương I 9 Cho nên, ví dụ: hello = r"This is a rather long string containingn several lines of text much as you would do in C." print hello sẽ in: This is a rather long string containingn several lines of text much as you would do in C. Hoặc, các chuỗi có thể được vây quanh trong một cặp nháy ba: """ hoặc . Cuỗi mỗi dòng không cần thêm dấu suỵt huyền khi dùng nháy ba, và chúng sẽ có mặt trong chuỗi. print """ Usage: thingy [OPTIONS] -h Display this usage message -H hostname Hostname to connect to """ xuất ra: Usage: thingy [OPTIONS] -h Display this usage message -H hostname Hostname to connect to Trình thông dịch in ra kết quả của các tác vụ chuỗi theo cùng cách như khi chúng được nhập vào: trong dấu nháy, và với các ký tự dấu nháy hay đặc biệt khác được thoát nghĩa (escape) bằng dấu suỵt huyền, để hiện giá trị thực. Chuỗi được kèm trong dấu nháy đôi nếu chuỗi chứa một dấu nháy đơn và không chứa dấu nháy đôi, ngoài ra nó sẽ được chứa trong các dấu nháy đơn. (Câu lệnh print , được giải thích sau, có thể dùng để viết các chuỗi không có dấu nháy hoặc thoát nghĩa.) Các chuỗi có thể được nối với nhau với toán tử + , và được lặp lại với *: >>> word = 'Help' + 'A' >>> word 'HelpA' >>> '<' + word*5 + '>' '<HelpAHelpAHelpAHelpAHelpA>' Hai chuỗi trực tiếp kế nhau được tự động nối với nhau; dòng đầu tiên bên trên có thể được biết "word = 'Help' 'A'"; việc này chỉ có tác dụng với hai chuỗi trực tiếp (string literal), không có tác dụng với các biểu thức chuỗi bất kỳ khác: >>> 'str' 'ing' # <- This is ok 'string' >>> 'str'.strip() + 'ing' # <- This is ok 'string' >>> 'str'.strip() 'ing' # <- This is invalid File "<stdin>", line 1, in ? 'str'.strip() 'ing' ^
  • 12. Chương I 10 SyntaxError: invalid syntax Các chuỗi có thể được chỉ mục (subscript hoặc index); như trong C, ký tự đầu tiên của một chuỗi có chỉ mục 0. Không có kiểu ký tự riêng; một ký tự chỉ đơn giản là một chuỗi có độ dài là một. Như trong Icon, chuỗi con có thể được chỉ định theo cách viết cắt lát (slice notation): hai chỉ mục phân cách bởi một dấu hai chấm. >>> word[4] 'A' >>> word[0:2] 'He' >>> word[2:4] 'lp' Các chỉ mục cắt lát có giá trị mặc định hữu dụng; chỉ mục đầu tiên có giá trị mặc định là không, chỉ mục thứ hai mặc định là kích thước của chuỗi đang bị cắt. >>> word[:2] # The first two characters 'He' >>> word[2:] # Everything except the first two characters 'lpA' Không như C, các chuỗi Python không thể bị thay đổi. Phép gán vào một vị trí chỉ mục trong một chuỗi sẽ gây ra lỗi: >>> word[0] = 'x' Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: object doesn't support item assignment >>> word[:1] = 'Splat' Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: object doesn't support slice assignment Tuy nhiên, việc tạo một chuỗi với nội dung gộp chung cũng dễ và hiệu quả: >>> 'x' + word[1:] 'xelpA' >>> 'Splat' + word[4] 'SplatA' Đây là một tính chất bất biến hữu dụng khác của tác vụ cắt lát: s[:i] + s[i:] bằng s. >>> word[:2] + word[2:] 'HelpA' >>> word[:3] + word[3:] 'HelpA' Các chỉ mục cắt lát giảm sinh (degenerate) được xử lý rất khéo: một chỉ mục quá lớn sẽ được thay bằng kích thước chuỗi, một giới hạn trên nhỏ hơn giới hạn dưới trả về một chuỗi rỗng. >>> word[1:100] 'elpA' >>> word[10:]
  • 13. 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ông phải cắt lát): >>> word[-100:] 'HelpA' >>> word[-10] # error Traceback (most recent call last): File "<stdin>", line 1, in ? IndexError: string index out of range Cách tốt nhất để nhớ hoạt động của cắt lát là nghĩ về các chỉ mục như đang trỏ vào giữa các ký tự, với cạnh trái của ký tự đầu tiên là 0. Sau đó cạnh phải của ký tự cuối cùng của một chuỗi của n ký tự có chỉ mục n, ví dụ: +---+---+---+---+---+ | H | e | l | p | A | +---+---+---+---+---+ 0 1 2 3 4 5 -5 -4 -3 -2 -1 Các số hàng đầu cho biết vị trí của các chỉ mục 0...5 trong chuỗi; dòng thứ hai cho biết các chỉ mục âm tương ứng. Một lát từ i tới j chứa toàn bộ các ký tự giữa các cạnh đánh số 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ủa word[1:3] là 2. Hàm có sẵn len() trả về độ dài của một chuỗi: >>> s = 'supercalifragilisticexpialidocious' >>> len(s) 34
  • 14. Chương I 12 Danh Sách Python biết một số kiểu dữ liệu gộp (compound) , dùng để nhóm các giá trị với nhau. Kiểu linh hoạt nhất là danh sách (list), có thể được viết như là một danh sách các giá trị phân cách bởi dấu phẩy ở giữa ngoặc vuông. >>> a = ['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ủa mộ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]
  • 15. 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
  • 16. Chương II 14 Chương II Đi vào Python Python 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ải phâ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.py Nế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àm Python 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ạn interface/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ủa nhữ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 python trả 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ông thì nó sẽ trả về một giá trị rỗng.
  • 17. 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ĩnh Nó 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 động Mộ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ểu nă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ểu integer, 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ấp Mộ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. Trong VBScript, 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ông cầ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àm Bạ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ủa mộ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úng bấ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ên phả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. Đây la 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ột thuộc tính của hàm. Mọi thứ là một đối tượng Hà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.
  • 18. 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ặc từ 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ặc cá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ái niệ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ạn không thể chỉ gọi buildConnectionString, nó phải là odbchelper.buildConnectionString. Nếu bạn đã từng dùng các lớ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ôn ngữ 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àm Perl, bạn xác nhận hàm của nó với module::function. Nhập tìm đường dẫn Trướ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ạn import 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ên trong 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ư sys module đượ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êm và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ết lậ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 đối tượ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ượng buộ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. Trong Python, đị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ó đối tượ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 được thô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 đối tượng, Hàm là các đối tượng, mudule cũng là các đối tượng.
  • 19. Chương III 17 Chương III Khá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 ta hiể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ỗi thứ đề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ương phá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àng minh 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ương trì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àm gì để 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ũng có 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âm củ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ới quanh 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ủa mì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òn số 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 tin nhâ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ằng chú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ình hướ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ới cá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ới theo 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. Đây là 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 theo mộ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ăng mớ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ác nhà 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ác quyể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ột phầ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
  • 20. 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ệu củ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ể (Instance variable). 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 được gọ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ào nhậ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ác biế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 định bở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ắn bó đó, 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ông phả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ương trì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ải Trong 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. Class Chỉ 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ũng như 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ủa class 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ột class 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ư trong Smalltalk, 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ợp cụ thể của class.
  • 21. 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 ảnh hưởng đối với ý nghĩa của mã Python có sử dụng các đối tượng khả biến như danh sách, từ điển, và đa số các kiểu thể hiện các vật ngoài chương trình (tập tin, cửa sổ, v.v...). Nó thường được dùng vì tên lóng có tác dụng như là con trỏ theo một vài khía cạnh nào đó. Ví dụ, truyền một đối tượng vào một hàm rẻ vì chỉ có con trỏ là được truyền, và nếu một hàm thay đổi một đối tượng được truyền vào, thì nơi gọi sẽ thấy các thay đổi đó -- thay vì cần hai kiểu truyền thông số như trong Pascal. Phạm vi trong Python và vùng tên Trước khi giới thiệu lớp, chúng ta sẽ cần hiểu phạm vi (scope) và vùng tên (namespace) hoạt động như thế nào vì các định nghĩa lớp sẽ sử dụng chúng. Kiến thức về vấn đề này cũng rất hữu dụng với những nhà lập trình Python chuyên nghiệp. 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ên như: 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ác tê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ụ hai module 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êm tiề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, real là 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 trong mô-đ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ác thuộ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ể được xó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 được tạ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át ra. Các câu lệnh được thực thi bởi lời gọi ở lớp cao nhất của trình thông dịch, vì đọc từ một kịch bản hoặc qua tương tác, được coi như một phần của 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ật ra cũng tồn tại trong một module; được gọi là __builtin__.)
  • 22. 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 vi lồng nhau mà vùng tên của chúng có thể được truy cập trực tiếp: phạm vi bên trong cùng, được tìm trước, chứa các tên nội bộ; các vùng tên của các hàm chứa nó, được tìm bắt đầu từ phạm vi chứa nó gần nhất (nearest enclosing scope); phạm vi giữa (middle scope), được tìm kế, chứa các tên toàn cục của module; và phạm vi ngoài cùng (được tìm sau cùng) là vùng tên chứa các tên có sẵn. Nếu một tên được khai báo là toàn cục, thì mọi tham chiếu hoặc phép gán sẽ đi thẳng vào phạm vi giữa chứa các tên toàn cục của 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ử khi vào các biến đó sẽ tạo một biến cục bộ mới trong phạm vi trong vùng, và không ảnh hưởng tới biến cùng tên ở phạm vi ngoài). 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ạm vi 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êm mộ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 định nghĩ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 định tĩ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ộc các tên và các đối tượng. Xóa cũng vậy: câu lệnh "del x" bỏ ràng buộc x khỏi vùng tên được tham chiếu tới bởi phạm vi nội bộ. Thực tế là mọi tác vụ có thêm các tên mới đều dùng phạm vi nội bộ: điển hình là các câu lệnh nhập và các định nghĩa hàm buộc tên 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ột biến cụ thể là ở phạm vi toàn cục.) Cái nhìn đầu tiên về class class 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 được cho 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.
  • 23. 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ọi phép gán vào các biến nội bộ đi vào vùng tên này. Đặc biệt, các định nghĩa hàm buộc tên của hàm mới ở đây. Khi rời khỏi một định nghĩa 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ĩa class) đượ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ác tê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ĩa class 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, theo thứ 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ương thứ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ường hợ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ạo trườ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)
  • 24. 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 được gá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 đối tượng. (Trong Python, từ phương thức không chỉ riêng cho trường hợp lớp: các kiểu đối tượng khác cũng có thể có phương thức. Ví dụ, đối tượng danh sách có phương thức tên append, insert, remove, sort, v.v... Tuy nhiên, trong phầ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ộc tí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ông phả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 (đối tượ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ông số, 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âng mộ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ói chung, 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ách thô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ượng trườ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 đó.)
  • 25. Chương III 23 Một vài lời bình Thuộc tính dữ liệu sẽ che thuộc tính phương thức cùng tên; để tránh vô tình trùng lặp tên, mà có thể dẫn đến các lỗi rất khó tìm ra trong các chương trình lớn, bạn nên có một quy định đặt tên nào đó để giảm thiểu tỉ lệ trùng lặp. Các quy định khả thi có thể gồm viết hoa tên phương thức, đặt tiền tố vào các tên thuộc tính dữ liệu (ví dụ như dấu gạch dưới _), 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ách khác, lớp không thể được dùng để cài đặt các kiểu dữ liệu trừu tượng tuyệt đối. Trong thực tế, không có gì trong Python có thể ép việc che dấu dữ liệu, tất cả đều dựa trên nguyên tắc. (Mặt khác, cài đặt Python, được viết bằng C, có thể dấu các chi tiết cài đặt và điểu khiển truy cập vào một đối tượng nếu cần; điều này có thể được dùng trong các bộ mở rộng Python viết bằng C.) Người dùng nên dùng các thuộc tính dữ liệu một cách cẩn thận, người dùng có thể phá hỏng những bất biến (invariant) được giữ bởi các phương thức nếu cố ý sửa các thuộc tính dữ liệu. Lưu ý rằng người dùng có thể thêm các thuộc tính dữ liệu riêng của họ vào đối tượng trường hợp mà không làm ảnh hưởng tính hợp lệ của các phương thức, miễn là không có trùng lặp tên, xin nhắc lại, một quy tắc đặt tên có thể giảm bớt sự đau đầu ở đây. Không có cách ngắn gọn để tham chiếu tới thuộc tính dữ liệu (hoặc các phương thức khác!) từ trong phương thức. Điều này thật ra giúp chúng ta dễ đọc mã vì không có sự lẫn lộn giữa biến nội bộ và biến trường hợp. Thông số đầu tiên của phương thức thường được gọi là self. Đây cũng chỉ là một quy ước: tên self hoàn toàn không có ý 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ên khó đọ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ủa class đó. 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ào mộ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ương thứ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 đọc cà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ục củ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
  • 26. 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àm và 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 định nghĩ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ừa Dĩ 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ác biể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 module khá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 ở trong class, 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ếu cầ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 khi gọi một phương thức của cùng một đối tượng, một phương thức của class cơ sở gọi một phương thức khác được định nghĩ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ên củ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 theo chiều sâu, và tìm trái qua phải. Do đó, nếu một thuộc tính không được tìm ra trong DerivedClassName, nó sẽ được
  • 27. 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 trong Base2, 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ên hơ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 hay trong 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ính củ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ặc dù dễ hiểu chuyện gì xảy ra trong vấn đề này (trường hợp sẽ có một bản chép duy nhất của ``các biến trường hợp của các thuộc tính dữ liệu dùng bởi lớp cơ sở chung), nó không rõ cho lắm nếu các ý nghĩa này thật sự hữu ích. Biến riêng Có 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 (textually replace) 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áo trộ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ủa trườ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ông phải lo về các biến trường hợp được định nghĩa bởi lớp con, hoặc việc sử dụng biến trường hợp bởi mã bên ngoài lớp. Lưu ý rằng việc xáo trộn tên được thiết kế chủ yếu để tránh trùng lặp; người quyết tâm vẫn có thể truy cập hoặc thay đổi biến riêng. Và điều này cũng có thể có ích trong các trường hợp đặc biệt, như trong trình gỡ rối, và đó là một lý do tại sao lỗ hổng này vẫn chưa được vá. 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ày cũ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ới hạ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ệu vào chung với nhau. Một định nghĩa lớp rỗng thực hiện được việc này: class Employee: pass john= Employee() # Create an empty employee record # Fill the fields of the record john.name = 'John Doe' john.dept = 'computer lab' john.salary = 1000 Với mã Python cần một kiểu dữ liệu trừu tượng, ta có thể thay vào đó một lớp giả lập các phương thức của kiểu dữ liệu đó. Ví dụ, nếu bạn có một hàm định dạng một vài dữ liệu trong một đối tượng tập tin, bạn có thể định nghĩa một lớp với các phương thức 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ức m, và m.im_func là đối tượng hàm tương ứng với phương thức.
  • 28. Chương III 26 Biệt lệ cũng là lớp Các biệt lệ được định nghĩa bởi người dùng cũng được định danh theo lớp. Bằng cách này, một hệ thống phân cấp biệt lệ có thể được tạo ra. Có hai dạng lệnh raise mới: raise Class, instance raise 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ứ hai là 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ới mộ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ực thi. 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ặp Bâ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 sau mà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ương thứ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:
  • 29. 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 ta mộ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ếu lớ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
  • 30. 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ông thườ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 ra rấ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ính nă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ày là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ạo Một vài bộ sinh đơn giản có thể được viết một cách xúc tích như các biểu thức bằng cách dùng một cú pháp giống như gộp danh sách (list comprehension) nhưng với ngoặc tròn thay vì ngoặc vuông. Các biểu thức này được thiết kế cho những khi bộ sinh được sử dụng ngay lập tức bởi hàm chứa nó. Biểu thức bộ sinh gọn hơn nhưng ít khả chuyển hơn là các định nghĩa bộ sinh đầy đủ và thường chiếm ít bộ nhớ hơn là gộp danh sách tương đương. 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']
  • 31. Chương IV 29 Chương IV Chươ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 tra cứ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ên chúng . Diving In Ví 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 đơn giả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ương trì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
  • 32. 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ơn Ví 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 Arguments Python 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 Functions Python 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ày là 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 function Hà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)
  • 33. 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 Function Ví 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:docbookdippyodbchelper.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 danh sá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 .
  • 34. 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 module chứ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 Function type, 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.
  • 35. Chương IV 33 Getting Object References with getattr Bạ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ần biế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ức pop . 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 , tham số 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ứ đối tượ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 Modules Ví 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
  • 36. 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 global variable. •• 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 Dispatcher Ví 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 List Python 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
  • 37. 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 or Trong 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 trong boolean 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.
  • 38. Chương IV 36 Using the and−or Trick Ví 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ậy and đượ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 functions Python 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 .
  • 39. Chương IV 37 Real−World lambda Functions Here 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 isnattest" >>> 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 together This 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 '
  • 40. 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 đó .
  • 41. 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ông thường , đừng lo lắng về những vấn đề bạn không hiểu . Vì dụ : fileinfo.py Có 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, return data.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])
  • 42. 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ần thay đổ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=31 name=/music/_singles/a_time_long_forgotten_con.mp3 year=1999 comment=http:/ / mp3. com/ ghostmachine album=Rave Mix artist=***DJ MARY−JANE*** title=HELLRAISER****Trance from Hell genre=31 name=/music/_singles/hellraiser.mp3 year=2000 comment=http:/ / mp3. com/ DJMARYJANE album=Rave Mix artist=***DJ MARY−JANE*** title=KAIRO****THE BEST GOA genre=31 name=/music/_singles/kairo.mp3 year=2000 Importing Modules Using from module import Python 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