pyqt5.files.wordpress.com · /mục lục ^ )*@/#l/ những bài viết trong tạp chí này...

44
Mục lục ^

Upload: others

Post on 29-Aug-2019

3 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 1 Mục lục ^

Phiên bản RC

fu l l ci rcleTẠP CHÍ ĐỘC LẬP CỦA CỘNG ĐỒNG NGƯỜI DÙNG UBUNTU LINUX

Số đặc biệt - chuyên đề lập trình

Tạp chí Full Circle không có bất cứ sự liên kết hay được sự hậu thuẫn bởi Canonical Ltd.

LL��PP TTRRÌÌNNHH PPYYTTHHOONNTT��PP 11

SSỐỐĐĐẶẶCC

BBIIỆỆTT

CCHHUUYYÊÊNNĐĐỀỀ

LLẬẬPPTTRRÌÌNNHH

Page 2: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 2 Mục lục ^

Phiên bản RC

Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0 Unported. Điều này cónghĩa là bạn có thể đọc, sao chép, chia sẻ và truyền bá rộng rãi với điều kiện: Bạn phải thể hiện bài viết là của tác giả theo cách nàođó (tối thiểu là tên, email hoặc URL) và hỗ trợ tạp chí này theo tên ("full circle magazine") và địa chỉ www.fullcirclemagazine.org

(nhưng không thể hiện các bài viết là của bạn hoặc bạn theo bất kì cách nào). Nếu bạn sửa chữa, thay đổi hoặc sử dụng những bài viết này, bạn phảichia sẻ kết quả theo cách tương tự.Tạp chí Full Circle hoạt động hoàn toàn độc lập đối với Canonical, nhà tài trợ của dự án Ubuntu, và những quan điểm cũng như ý kiếntrong tạp chí hoàn toàn không thể hiểu là được sự hậu thuẫn của Canonical.

fu l l ci rcleTẠP CHÍ ĐỘC LẬP CỦA CỘNG ĐỒNG NGƯỜI DÙNG UBUNTU LINUX

Phần 1 : Làm quen với Python

Phần 2: Làm quen với Python (tt)

Phần 3: Mô-đun và Hàm

Phần 4: Lớp trong Python

Phần 5: Lập trình giao diện đồ họa

Phần 6: Lập trình giao diện đồ họa (tt)

Phần 7: Lập trình cơ sở dữ liệu

Phần 8: Lập trình cơ sở dữ liệu (tt)

Nhóm Full Circle

Chủ biên - Ronnie [email protected]ản lí website - Rob [email protected]ản lí truyền thông - [email protected]ên tập và hiệu đínhMike KennedyDavid HaasGord CampbellXin gửi lời cảm ơn đến công tyCanonical, nhóm quảng bá Ubuntuvà nhiều nhóm biên dịch trên khắpthế giới.

Dự án biên dịch tạp chí Full Circle:http://tapchifc.pbworks.com

Page 3: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 3 Mục lục ^

Phiên bản RC

Giữa vô vàn ngôn ngữlập trình hiện nay,Python là ngôn ngữdễ học nhất. Python

ra đời vào cuối thập niên 80của thế kỷ trước và phát triểnkhông ngừng. Nó mặc địnhđược cài đặt sẵn trong hầu hếtcác bản phân phối Linux, vàthường được người ta chú ýđến khi quyết định học mộtngôn ngữ lập trình. Chúng ta sẽlàm quen với lập trình dònglệnh trong bài viết này. Sắp tớichúng ta sẽ khám phá lập trìnhgiao diện đồ họa GUI(Graphical User Interface). Bâygiờ, hãy bắt tay vào xây dựngmột ứng dụng đơn giản.Chương trình đầu tiên

Hãy dùng một trình soạnthảo văn bản như gedit để gõmột vài dòng mã lệnh. Sau đóxem cách chúng hoạt động.

Gõ 4 dòng sau:#! /usr/bin/env python

print ' Hello. I am a pythonprogram. '

name = raw_input( "What isyour name? " )

print "Hello there, " + name+ " ! "

Lưu tập tin lại với tên"hello.py" vào nơi nào bạnmuốn. Tôi đề nghị các bạn tạomột thư mục tênpython_examples trong thưmục chính (home) và đặt nóvào trong. Ví dụ đơn giản nàycho thấy lập trình Python dễnhư thế nào. Trước khi có thểchạy chương trình, chúng taphải thiết lập thuộc tính thựcthi cho nó. Mở một cửa sổ dònglệnh và chuyển dấu nhắc vàotrong thư mục mà bạn vừa lưutập tin rồi gõ:chmod +x hello. py

Bây giờ hãy chạy chương trình:

greg@earth:~/python_examples

$ . /hello. py

Hello. I am a pythonprogram.

What is your name? FerdBurphel

Hello there, Ferd Burphel!

greg@earth: ~/python_examples$

Thật đơn giản phải không.Bây giờ, hãy nhìn lại từng dònglệnh.#! /usr/bin/env python

Dòng này báo cho hệ thốngbiết đây là chương trình viếtbằng Python và dùng bộ thôngdịch python mặc định để thựcthi chương trình.print ' Hello. I am a pythonprogram. '

Dòng này sẽ in ra câu"Hello. I am a python program."trong cửa sổ dòng lệnh.name = raw_input( "What isyour name? " )

Cái này hơi phức tạp chút.Có hai phần trong dòng này.Đầu tiên là name =, và thứ hailà raw_input("What is yourname? "). Chúng ta sẽ xemphần thứ hai trước. Lệnhraw_input sẽ in câu ("What is

your name?") ra cửa sổ dònglệnh và nó sẽ đợi người dùng(các bạn) nhập vào nội dung gìđó (kết thúc bằng phím{Enter}). Bây giờ hãy quay lạiphần đầu: name =. Phần nàysẽ gán giá trị vào một biến tênlà "name". Thế biến là gì? Hãytưởng tượng biến là một cáihộp dùng để chứa đồ, giày dép,linh kiện máy tính, giấy tờ, bấtkể thứ gì. Trong trường hợpnày, nó chứa những gì bạnnhập. Vì vậy tôi đã nhập FerdBurphel. Trong ví dụ này,Python chỉ đơn giản lấy dữ liệunhập và cất vào chiếc hộp"name" để dùng sau này.print "Hello there, " + name+ " ! "

Một lần nữa, chúng ta sửdụng câu lệnh "print" để hiểnthị thông tin trên màn hình, đólà "Hello there, ", cộng với dữliệu có trong biến "name", vàmột dấu chấm than ở cuối câu.Ở đây chúng ta nối hay nóicách khác là đặt gần nhau bamảnh thông tin: "Hello there",thông tin trong biến "name" và

LÀM TH� NÀOViết bởi Greg Walters

L�p trình Python — Ph�n 1

Page 4: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 4 Mục lục ^

Phiên bản RC

dấu chấm than.Bây giờ, hãy dành một chút

thời gian để tìm hiểu sâu hơntrước khi chúng ta đi đến một vídụ khác. Mở cửa sổ dòng lệnhvà gõ:python

Các bạn sẽ thấy điều gì đótương tự thế này:greg@earth: ~/python_examples$python

Python 2. 5. 2 (r252: 60911, Oct5 2008, 19: 24: 49)

[ GCC 4. 3. 2] on linux2

Type "help" , " copyright" ," credits" or " license" formore information.

>>>

Các bạn đang ở trong giaodiện shell của Python. Từ đây,các bạn có thể làm được nhiềuđiều, nhưng hãy xem chúng tacó gì trước khi đi tiếp. Đầu tiên,các bạn nên lưu ý số phiên bảnpython - ở đây là 2.5.2. Kế đến,các bạn thấy câu thông báorằng để được giúp đỡ, hãy gõ

"help" tại dấu nhắc. Tôi sẽ đểcác bạn tự làm điều đó. Bây giờhãy nhập:print 2+2

và nhấn enter. Các bạn sẽ nhậnđược>>> print 2+24>>>

Lưu ý rằng chúng ta viết từ"print" dưới dạng chữ thường.Điều gì sẽ xảy ra nếu chúng taviết thành "Print 2+2"? Câu trảlời của trình thông dịch sẽ là:>>> Print 2+2

File "<stdin>" , line 1Print 2+2

^SyntaxError: invalid syntax>>>

Bởi vì chỉ tồn tại lệnh "print"chứ không phải "Print". Phânbiệt chữ hoa – thường rất quantrọng trong Python.

Bây giờ hãy vui đùa với biếnthêm một chút nữa. Gõ:var = 2+2

Bạn sẽ thấy không có gì xảyra ngoại trừ Python trả về dấu

nhắc “>>>”. Không có gì saiđâu. Chúng ta muốn Python tạomột biến (chiếc hộp) tên là varvà bỏ vào đấy tổng của “2+2”.Để xem var chứa gì, gõ:print var

và nhấn enter.>>> print var4>>>

Bây giờ chúng ta có thể sửdụng var bao nhiêu lần tuỳthích thay cho số 4, như thếnày:>>> print var * 28>>>

Nếu chúng ta gõ lại “printvar” thì sẽ nhận được:>>> print var4>>>

var chẳng thay đổi. Nó vẫnlà tổng của 2+2, là 4.

Dĩ nhiên đây là chương trìnhđơn giản cho bài hướng dẫn mởđầu này. Độ phức tạp sẽ tăngdần trong những bài kế tiếp.

Nhưng bây giờ hãy xem tiếpmột vài ví dụ về biến.

Vẫn trong trình thông dịch,gõ:>>> strng = ' The time hascome for all good men to cometo the aid of the party! '

>>> print strng

The time has come for allgood men to come to the aidof the party!

>>>

Các bạn vừa tạo một biếntên “strng” (viết tắt của string)chứa giá trị 'The time has comefor all good men to come to theaid of the party!'. Từ bây giờ(miễn là chúng ta đừng thoátkhỏi bộ thông dịch này), biếnstrng sẽ giữ nguyên giá trị trừphi chúng ta thay đổi nó. Điềugì sẽ xảy ra nếu chúng ta thửnhân biến này với 4?>>> print strng * 4

The time has come for allgood men to come to the aidof the party! The time hascome for all good men to cometo the aid of the party! Thetime has come for all goodmen to come to the aid of the

LẬP TRÌNH PYTHON - PHẦN 1

Page 5: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 5 Mục lục ^

Phiên bản RC

party! The time has come forall good men to come to theaid of the party!

>>>

Chao ôi, nó không đúng nhưnhững gì chúng ta mong đợi,phải không? Nó in giá trị củabiến strng 4 lần. Tại sao? Trìnhthông dịch hiểu rằng strng làmột chuỗi ký tự, không phải làmột giá trị số. Các bạn khôngthể biểu diễn một phép toánvới một chuỗi.

Điều gì sẽ xảy ra nếu chúngta có một biến tên s chứa chữsố '4' (ký tự) như sau:>>> s = ' 4'>>> print s4

Có vẻ như s chứa một sốnguyên 4, nhưng không phảivậy. Thực tế là nó chứa mộtchuỗi thể hiện chữ số 4. Vậy,nếu chúng ta gõ 'print s * 4'thì...>>> print s*44444>>>

Một lần nữa, trình thông dịchhiểu rằng s là một chuỗi, khôngphải là giá trị số. Bởi vì chúng

ta bọc số 4 trong cặp nháy đơn,biểu diễn một chuỗi.

Chúng ta có thể chứng minhđiều này bằng cách gõ printtype(s) để xem kiểu dữ liệu củabiến.>>> print type(s)<type ' str' >>>>

Chính xác! Đó là một kiểuchuỗi. Nếu chúng ta muốndùng nó như một giá trị số, tasẽ làm như sau:>>> print int(s) * 416>>>

Chuỗi (s), chứa giá trị '4', giờđã được chuyển thành sốnguyên và được nhân với 4 chokết quả 16.

Vừa rồi, các bạn đã được giớithiệu lệnh print, raw_input,cách gán biến và sự khác biệtgiữa chuỗi và số nguyên.

Hãy cùng tôi đi xa thêm chútnữa. Trong trình thông dịchPython, gõ quit() để thoát rangoài dấu nhắc của cửa sổdòng lệnh.

Vòng lặp For đơn giản

Bây giờ hãy khám phá cáchlập trình một vòng lặp đơngiản. Quay lại trình soạn thảovăn bản và gõ đoạn mã sau:#! /usr/bin/env python

for cntr in range(0, 10) :

print cntr

Đừng quên dùng phím Tabđể thụt lề trước dòng “printcntr”. Điều này rất quan trọng,Python không dùng dấu ngoặcđơn “(“ hoặc dấu ngoặc nhọn“{“ như những ngôn ngữ lậptrình khác để biểu thị khối mãlệnh. Thay vào đó, nó căn cứvào sự thụt lề đầu dòng.

Lưu chương trình với tên“for_loop.py”. Trước khi thửchạy nó, hãy tìm hiểu vòng lặpfor là gì.

Một vòng lặp là một khối mãlệnh thực hiện một công việc cụthể và kèm theo số lần thựchiện. Trong trường hợp này,chúng ta sẽ cho lặp 10 lần, ingiá trị của biến cntr (viết tắtcủa counter). Diễn giải ra là“gán biến cntr bằng 0, thực

hiện 10 lần việc in giá trị củacntr lên màn hình, cộng 1 vàocntr sau mỗi chu kỳ thực hiện.”Đoạn mã “range(0,10)” nóirằng hãy bắt đầu ở 0, lặp chođến khi giá trị của cntr là 10,rồi kết thúc vòng lặp.

Quay trở lại cửa sổ dònglệnh, trước khi chạy, nhớ:chmod +x for_loop. py

và bây giờ chạy chươngtrình. /for_loop. py

greg@earth: ~/python_examples$. /for_loop. py0123456789greg@earth: ~/python_examples$

Xem, có vẻ nó đã chạyđúng, nhưng tại sao nó chỉ đếmđến 9 rồi dừng lại. Nhìn lại kếtquả xuất ra. Có 10 số đã đượcin, bắt đầu từ 0 và kết thúcbằng 9. Đó là điều chúng ta yêu

PROGRAM IN PYTHON - PART 1

Page 6: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 6 Mục lục ^

Phiên bản RCPROGRAM IN PYTHON - PART 1

cầu máy làm - in giá trị củacntr 10 lần, thêm 1 vào biếnmỗi lần, và kết thúc khi giá trịbằng 10.

Các bạn có thể thấy rằng,việc lập trình trông đơn giản,những cũng phức tạp khôngkém và các bạn cần biết chắcmình yêu cầu máy làm gì. Nếubạn thay đổi câu lệnh rangethành “range(1,10)”, nó sẽ bắtđầu đếm từ 1, nhưng kết thúcbằng 9, vì khi cntr bằng 10,vòng lặp tự thoát. Vậy để nó in“1,2,3,4,5,6,7,8,9,10”, chúng tasẽ ghi range(1,11). Suy ra làvòng lặp sẽ kết thúc khi nó đạtđến chỉ số trên của giới hạn.

Ngoài ra, cần lưu ý đến cúpháp của câu lệnh. Đó là “fortên_biến in range(giá trị bắtđầu, giá trị cuối):”. Dấu haichấm “:” có nghĩa là chúng tasắp bắt đầu một khối mã bêndưới. Điều quan trọng là khôngđược quên dấu hai chấm “:” vàthụt lề khối mã bên dưới chođến khi nó kết thúc.

Nếu chúng ta thay đổi nộidung chương trình như sau:#! /usr/bin/env python

for cntr in range(1, 11) :

print cntr

print ' All Done'

Chúng ta sẽ nhận được...greg@earth: ~/python_examples$. /for_loop. py12345678910All Donegreg@earth: ~/python_examples$

Hãy đảm bảo rằng bạn thụtlề đúng. Luôn nhớ rằng sự thụtlề báo hiệu một khối mã lệnh.Chúng ta sẽ tìm hiểu nhiều hơnvề thụt lề trong bài học tới.

Đó là những gì của bài họchôm nay. Lần tới chúng ta sẽ ônlại và đi tiếp với nhiều câu lệnhlập trình python hơn. Trong lúcchờ đợi, các bạn có thể thử càiđặt một trình soạn thảo pythonnhư là Dr. Python hoặc SPE(Stani's Python Editor), cả haiđều có thể cài đặt thông quaSynaptic.

Greg Walters is owner ofRainyDay Solutions, LLC, aconsulting company in Aurora,Colorado, and has beenprogramming since 1972. Heenjoys cooking, hiking, music,and spending time with hisfamily.

Page 7: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 7 Mục lục ^

Phiên bản RC

LÀM TH� NÀOViết bởi Greg Walters

L�p trình Python — Ph�n 2

Trong bài lần trước,chúng ta đã được thấymột chương trình đơngiản sử dụng raw_input

để lấy sự tương tác từ ngườidùng, một số kiểu biến đơngiản, và một vòng lặp đơn giảnsử dụng biểu thức "for". Ở bàinày chúng ta sẽ tập trungnhiều hơn vào các biến, và thửviết vài chương trình.Danh sách

Giờ chúng ta sẽ tìm hiểu một

kiểu biến khác đó là kiểu danhsách. Ở những ngôn ngữ khác,một danh sách có thể được xétnhư một mảng. Hãy liên tưởngtới những cái hộp đựng giầy,một mảng (hay danh sách) sẽlà một số lượng các hộp đượcdán lại cạnh nhau và ở mỗi hộpđều chứa một đồ vật. Ví dụ,chúng ta có thể đặt dĩa trongmột cái hộp, dao ở cái hộpkhác, và thìa ở một cái khác.Hãy xem một danh sách đơngiản. Một cách dễ dàng để hìnhdung là danh sách các thángtrong năm. Chúng ta có đoạnmã như thế này:months =[ ' Jan' , ' Feb' , ' Mar' , ' Apr' , ' May' , ' Jun' , ' Jul' , ' Aug' , ' Sep' , ' Oct' , ' Nov' , ' Dec' ]

Để tạo một danh sách,chúng ta chúng ta nhóm tất cảcác giá trị vào trong một cặpngoặc vuông ( '[' và ']' ). Chúngta đặt tên danh sách là'months'. Để sử dụng nó, chúngta có thể gọi kiểu như: printmonths[0] hoặc months[1] (nósẽ in ra 'Jan' hoặc 'Feb'). Nhơslaf chúng ta luôn luôn đếm từ

0. Để tìm độ dài của danh sách,chúng ta có thể sử dụng:print len(months)

nó sẽ trả về 12.Một ví dụ khác về danh sách

là danh mục các sách nấu ăn.Ví dụ:catagories = [ ' Main dish' ,' Meat' , ' Fish' , ' Soup' ,' Cookies' ]

Như trên thì categories[0] sẽlà 'Main dish', và categories[4]sẽ là 'Cookies'. Rất đơn giản.Tôi nghĩ rằng bạn có thể nghĩ rarất nhiều thứ có thể sử dụngdanh sách.

Đến giờ chúng ta đã tạo mộtdanh sách sử dụng các xâu đểchưa thông tin. Chúng ta cũngcó thể tạo một danh sách sửdụng các số nguyên. Nhìn lạidanh sách months, chúng ta cóthể tạo một danh sách chứa sốngày của mỗi tháng:DaysInMonth =[ 31, 28, 31, 30, 31, 30, 31, 31, 30, 3

1, 30, 31]

Nếu in ra DaysInMonth[1](cho tháng 2) chúng ta sẽ được28, nó là một số nguyên. Để ýrằng tôi lấy tên của danh sáchlà DaysInMonth. Không khókhăn gì nếu tôi lấy nó là'daysinmonth' hoặc đơn giảnchỉ là 'X'... nhưng nó hơi khóđọc. Những lập trình viên giỏiluôn yêu cầu các tên của biếnphải dễ hiểu. Chúng ta sẽ đivào chi tiết về vấn đề này sau.Chút nữa chúng ta sẽ nói thêmvề danh sách.

Trước khi chúng ta đến vớichương trình ví dụ tiếp theo,hãy xem một vài thứ khác vềPython.Nói thêm về Xâu

Chúng ta đã nói qua về xâuở phần 1. Bây giờ đi sâu hơnmột chút về chuỗi. Một xâu làmột danh sách các kí tự. Khôngcòn cách giải thích nào ngắngọn hơn. Thực tế, bạn có thểcoi một xâu như là một mảngcác kí tự. Ví dụ nếu chúng ta

Hiệu đính phần 1David Turner đã gửi thư cho tôi nóivề việc sử dụng Tab để thụt lề chomã nguồn chương trình sẽ gây mộtchút lầm lẫn cho những trình soạnthảo sử dụng nhiều hoặc ít hơn 4khoảng trắng một đoạn thụt lề.Điều này đúng. Nhiều lập trình viênPython (có cả tôi) tiết kiệm thờigian bằng cách đặt một tab trongtrình soạn thảo của họ là bốnkhoảng trắng. Vấn đề ở đây là cónhững người sử dụng những trìnhsoạn thảo mà cài đặt khác bạn, nócó thể làm cho đoạn mã nguồn nhìnkhông được đẹp và có thể gặp mộtsố rắc rối. Vì vậy hãy tập thói quensử dụng khoảng trắng thay vì sửdụng Tab.

Page 8: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 8 Mục lục ^

Phiên bản RC

gắn xâu 'The time has come'vào biến tên là strng, và sau đómột biết kí tự thứ 2 của xâu làgì, chúng ta thử gõ:strng = ' The time has come'print strng[ 1]

Kết quả sẽ là 'h'. Nhớ rằngchúng ta luôn luôn đếm từ 0, vìvậy kí tự đầu tiên sẽ là [0], thứhai là [1], thứ 3 sẽ là [2], và cứthế. Nếu chúng ta muốn tìmnhững kí tự bắt đầu từ vị trí 4đến vị trí 8, chúng ta gõ:print strng[ 4: 8]

nó sẽ trả về 'time'. Như vònglặp for ở phần một, bộ đếmdừng lại ở 8, nhưng không trảvề kí tự thứ 8, đó là khoảngtrắng đằng sau 'time'.

Chúng ta có thể tìm độ dàicủa xâu bằng cách sử dụnghàm len():print len(strng)

nó sẽ trả về 17. Nếu chúngta muốn tìm từ 'time' nằm ở vịtrí nào của xâu, có thể sử dụngpos = strng. find( ' time' )

Bây giờ, biến pos (viết gọncủa position) là 4, cho thấy từ'time' bắt đầu ở vị trí 4 của xâu.Nếu chúng ta dùng hàm find đểtìm một từ hoặc một chuỗikhông có trong xâu như sau:pos = strng. find( ' apples' )

sẽ trả về giá trị -1 cho biếnpos.

Chúng ta cũng có thể lấy racác từ riêng lẻ trong xâu bằngcách sử dụng lệnh split. Chúngta sẽ cắt (hoặc bẻ gãy) xâu tạimỗi khoảng trắng sử dụng:print strng. split( ' ' )

nó sẽ trả về một danh sáchchứa ['The', 'time', 'has','come']. Đây là một hàm rấthữu ích. Ngoài ra còn có nhiềuhàm khác thao tác với xâu,chúng ta sẽ sử dụng chúng saunày.Thay thế chuỗi

Có một việc nữa mà tôimuốn nói đến trước khi chúngta bước vào chương trình ví dụtiếp theo. Khi chúng ta muốn inra cái gì đó bao gồm nhữngđoạn văn bản và cả các biến,

chúng ta có thể sử dụng Thaythế biến. Làm việc này khá đơngiản. Nếu chúng ta muốn thaythế một xâu, chúng ta sử dụng'%s' và chỉ định vị trí sẽ thaythế. Ví dụ, để in ra một thángtừ danh sách bên trên, chúng tacó thể sử dụng:print ' Month = %s' %kmonth[ 0]

Nó sẽ in ra 'Month = Jan'.Nếu bạn muốn thay thế một sốnguyên, sử dụng '%d'. Hãy xemví dụ bên dưới:Months = [ ' Jan' , ' Feb' ,' Mar' , ' Apr' , ' May' , ' Jun' ,' Jul' , ' Aug' , ' Sep' , ' Oct' ,' Nov' , ' Dec' ]DaysInMonth =[ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]for cntr in range(0, 12) :

print ' %s has %d days. '%(Months[ cntr] ,DaysInMonth[ cntr] )

Kết quả của đoạn mã trên sẽlà:Jan has 31 days.Feb has 28 days.Mar has 31 days.Apr has 30 days.May has 31 days.Jun has 30 days.Jul has 31 days.Aug has 31 days.Sep has 30 days.

Oct has 31 days.Nov has 30 days.Dec has 31 days.

Cái quan trọng cần hiểu ởđây là sử dụng nháy đơn vànháy kép. Nếu bạn đặt mộtbiến kiểu xâu như sau:st = ' The time has come'

hoặc như sau:st = “The time has come”

kết quả là tương tự nhau. Tuyvậy, nếu bạn cần thêm một dấunháy đơn trong xâu như sau:st = ' He said he' s on hisway'

bạn sẽ gặp phải lổi cú pháp.Bạn cần phải khởi tạo nó nhưsau:st = “He said he' s on hisway”

Nghĩ theo cách này. Để địnhnghĩa một xâu, bạn phải đặt nóvào trong một cặp dấu nháy(đơn hoặc kép) – một ở đầu vàmột ở cuối. Nếu bạn cần dùngnhiều loại dấu nháy, sử dụngcặp dấu nháy ngoài cùng là loạimà không xuất hiện trong xâu

LẬP TRÌNH PYTHON - PHẦN 2

Page 9: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 9 Mục lục ^

Phiên bản RC

như ở ví dụ trên. Nhưng bạnmuốn hỏi, làm thế nào để khaibáo một xâu dạng “She said“Don't Worry””? Trong trườnghợp này, bạn có thể định nghĩanó như sau:st = ' She said “Don\' tWorry”'

Chú ý dấu xổ chéo trước dấunháy đơn trong 'Don't'. Nó đượcgọi là kí tự thoát, và báo choPython biết rằng in ra một dấunháy đơn chứ không phải làmột dấu định nghĩa xâu. Mộtvài kiểu dùng kí tự thoát khácnhư '\n' cho dòng mới, và '\t'cho một tab. Chúng ta sẽ dùngchúng ở những ví dụ sau này.Phép gán và biểu thức

bằng nhau

Chúng ta cần học thêm vàithứ để có thể làm ví dụ tiếptheo. Đầu tiên là sự khác nhaugiữa phép gán và 2 biểu thứcbằng nhau. Chúng ta đã sửdụng phép gán nhiều lần trongnhững ví dụ. Khi chúng ta muốnđặt một giá trị cho một biến,chúng ta sử dụng phép gán,chúng ta sử dụng toán tử gán'=' (dấu bằng):

variable = value

Tuy vậy, khi chúng ta muốnước lượng một biến và một giátrị, chúng ta phải sử dụng toántử so sánh. Khi chúng ta muốnkiểm tra xem một biến có bằngmột giá trị xác định nào đókhông, chúng ta sử dụng '=='(2 dấu bằng):variable == value

Vì vậy, nếu chúng ta có mộtbiến tên là looop và chúng tamuốn biểu diễn nếu nó bằng12, sử dụng:if loop == 12:

Đừng lo lắng về if và dấu haichấm ở ví dụ trên. Chỉ cần nhớrằng chúng ta phải sử dụng 2dấu bằng để ước lượng.Chú thích

Điều tiếp theo chúng ta cầnbàn tới là chú thích. Chú thíchquan trọng cho nhiều việc.Không chỉ cho bạn hoặc ai đóthấy ý tưởng bạn đang làm, khibạn quay lại với đoạn mã củamình sau 6 tháng, bạn có thểnhớ rõ bạn đang muốn làm gì.Khi bạn bắt đầu viết nhiều

chương trình, chú thích sẽ trởnên rất quan trọng. Chú thíchcũng cho phép bạn làm Pythonbỏ qua những dòng mã này. Đểchú thích một dòng bạn sửdụng dấu '#'. Ví dụ:# This is a comment

Bạn có thể đặt chú thích bấtcứ đâu trên một dòng mã,nhưng nhớ rằng, khi đó Pythonsẽ bỏ qua những thứ sau dấu'#'.Biểu thức if

Bây giờ chúng ta sẽ trở lạivới biểu thức if trong ví dụ ngắnbên trên. Khi chúng ta muốnlàm một việc dựa trên giá trịcủa cái gì đó, chúng ta sử dụngbiểu thức if:if loop == 12:

Nó sẽ kiểm tra biến 'loop',và, nếu giá trị là 12, thì sẽ làmmọi thứ ở khối thụt lề bên dưới.Nhiều trường hợp, như vậy làđủ, nhưng, khi bạn muốn dùng,nếu một biến bằng gì đó, thìlàm cái này, không thì làm cáikia. Chúng ta có thể hình dungbằng đoạn mã giả sau:

if x == y thendo something

elsedo something

và trong Python chúng ta cóthể viết:if x == y:

do somethingelse:

do something elsemore things to do

Những ý chính cần nhớ là:2. Kết thúc biểu thức if hoặcelse là dấu hai chấm.1. Thụt lề các dòng mã của bạn

Hãy tự mình kiểm tra, bạn cóthể sử dụng if/elif/else. Ví dụ:x = 5if x == 1:

print ' X is 1'elif x < 6:

print ' X is less than6'elif x <10:

print ' X is less than10'else:

print ' X is 10 orgreater'

Chú ý rằng chúng ta sử dụngtoán tử '<' để xác định nếu xNHỎ HƠN một gái trị nào đó –

LẬP TRÌNH PYTHON - PHẦN 2

Page 10: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 1 0 Mục lục ^

Phiên bản RC

trong trường hợp này là 6 hoặc10. Những biểu thức so sánhthường dùng khác là lớn hơn'>', nhỏ hơn hoặc bằng '<=',lớn hơn hoặc bằng '>=', vàkhông bằng '!='.Biểu thức while

Cuối cùng, chúng ta sẽ xemmột ví vụ đơn giản của biểuthức wile. Biểu thức while chophép bạn tạo một vòng lặp làmhàng loạt những việc, cứ nhưvậy cho đến khi đặt tới một giớihạn xác định nào đó. Một ví dụđơn giản là gắn một biến “loop”là 1. Sau đó khi biến loop có giátrị nhỏ hơn hoặc bằng 10 thì ingiá trị của loop, thêm 1 vàoloop và tiếp tục, đến khi looplớn hơn 10 thì dừng lại:loop = 1while loop <= 10:

print looploop = loop + 1

chạy trong cửa sổ dòng lệnhchúng ta sẽ được như sau:1234567

8910

Đây chính là điều chúng tamuốn thấy. Minh họa 1 (ở trên,phải) là một ví dụ tương tự,nhìn có vẻ rắc rối hơn, nhưngvẫn đơn giản.

Trong ví dụ này, chúng ta kếthợp biểu thức if, vòng lặp while,biểu thức đầu vào, kí tự thoátthể hiện dòng mới, toán tử gán,và các toán tử so sánh – tất cảtrong chương trình có 8 dòng.

Chạy ví dụ này sẽ đượcEnter something or ' quit' toend=> FROG

You typed FROGEnter something or ' quit' toend=> bird

You typed birdEnter something or ' quit' toend=> 42

You typed 42Enter something or ' quit' toend=> QUIT

You typed QUITEnter something or ' quit' toend=> quit

quitting

Chú ý rằng khi chúng ta gõ'QUIT', chương trình khôngdùng. Bởi vì chúng ta ước lượnggiá trị của biến trả về là 'quit'(response == 'quit'). 'QUIT'không bằng 'quit'.

Trước khi kết thúc tháng này,chúng ta tới với một ví dụ ngắnkhác. Hãy viết bạn muốn kiểmtra xem nếu một người dùngđược phép truy cập chươngtrình. Ví dụ này không phải làcách tốt nhất để làm việc này,nhưng nó tốt để thực hành vớinhững gì chúng ta đã học.

Đơn giản, chúng ta sẽ hỏingười dùng tên và mật khẩu, sosánh chúng với thông tin đãviết bên trong chương trình, vàsau đó thực hiện quyết địnhdựa trên những gì chúng tathấy. Chúng ta sẽ sử dụng haidanh sách – một để chứa nhữngngười dùng được phép và mộtđể chứa mật khẩu. Sau đó

chúng ta sẽ sử dụng raw_inputđể lấy thông tin từ người dùng,và cuối cùng sử dụng if/elif/elseđể kiểm tra và quyết định nếungười dùng đó được phép. Nhớrằng, đấy không phải là cáchtốt nhất để làm điều này. Chúngta sẽ đi vào những cách khác ởcác bài sau. Đoạn mã củachúng ta ở ô bên phải.

Lưu lại thành'password_test.py' và chạy vớinhiều đầu vào khác nhau.

Chỉ còn một thứ chúng tachưa nói đến là việc kiểm tradanh sách ở đoạn mã bắt đầuvới 'if username in users:'.Chúng ta sẽ làm gì để kiểm traxem nếu tên người dùng đượcnhập vào có trong danh sách.Nếu nó có, chúng ta sẽ lấy đượcvị trí của tên người dùng trongdanh sách người dùng. Sau đóchúng ta sử dụngusers.index(usrname) để lấy vị

loop = 1while loop == 1:

response = raw_input( " Enter something or ' quit' toend => " )

if response == ' quit' :print ' quitting'loop = 0

else:print ' You typed %s' % response MH. 1

LẬP TRÌNH PYTHON - PHẦN 2

Page 11: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 1 1 Mục lục ^

Phiên bản RC

trí trong danh sách người dùngnhư vậy chúng ta có thể lấymật khẩu, nó được đặt cùng vịtrí ở danh sách mật khẩu. Ví dụ,John là ở vị trí 1 trong danhsách người dùng. Mật khẩu củaanh ấy, 'dog' là ở vị trí 1 trongdanh sách mật khẩu. Theo cáchnày chúng ta có thể lấy ra cáccặp.Vậy là đủ cho tháng này.Tháng tới, chúng ta sẽ họcvề các hàm và mo-đun.Trong khi chờ đợi, hãy thựchành với những gì bạn đãhọc được và chúc vui vẻ.

#-----------------------------------------------#password_test. py# example of if/else, lists, assignments, raw_input,# comments and evaluations#-----------------------------------------------# Assign the users and passwordsusers = [ ' Fred' , ' John' , ' Steve' , ' Ann' , ' Mary' ]passwords = [ ' access' , ' dog' , ' 12345' , ' kids' , ' qwerty' ]#-----------------------------------------------# Get username and passwordusrname = raw_input( ' Enter your username => ' )pwd = raw_input( ' Enter your password => ' )#-----------------------------------------------# Check to see if user is in the listif usrname in users:

position = users. index(usrname) #Get the position in the list of the usersif pwd == passwords[ position] : #Find the password at position

print ' Hi there, %s. Access granted. ' % usrnameelse:

print ' Password incorrect. Access denied. 'else:

print "Sorry. . . I don' t recognize you. Access denied. "

Greg Walters là chủ củaRainyDay Solutions, LLC, mộtcông ty tư vấn ở Aurora, Colorado,là lập trình viên từ năm 1 972. Ôngthích nấu nướng, đi bộ đường dài,nghe nhạc và dành thời gian chogia đình.

LẬP TRÌNH PYTHON - PHẦN 2

Page 12: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 1 2 Mục lục ^

Phiên bản RC

LÀM TH� NÀOViết bởi Greg Walters

L�p trình Python — Ph�n 3Trong bài viết trước,chúng ta đã học vềdanh sách, kí tự thaythế, chú thích, phép gán

và biểu thức bằng nhau, câulệnh if và while. Tôi đã hứa vớicác bạn là trong bài viết nàychúng ta sẽ được học về mô-đunvà hàm. Vậy thì chúng ta hãybắt đầu.Mô-đun

Mô-đun là một cách để có thểmở rộng việc lập trình Pythoncủa bạn. Bạn có thể tự tạo ramô-đun riêng của mình hoặc sửdụng những cái sẵn có củaPython, hoặc sử dụng những cáingười khác đã tạo ra. Bản thânPython có sẵn hàng trăm mô-đun tạo thuận lợi cho việc lậptrình của bạn. Danh sách cácmô-đun sẵn có của Python cóthể tìm thấy tạihttp://docs.python.org/modindex.html. Một vài mô-đun phụ thuộcvào đặc trưng của hệ điều hành,nhưng hầu hết đều hỗ trợ đanền tảng (có thể được sử dụngtrên Linux, Mac và MicrosoftWindows). Để có thể sử dụng

một mô-đun ngoài, bạn phảinạp mô-đun đó vào chươngtrình của mình. Một trongnhững mô-đun sẵn có củaPython tên là 'random'. Mô-đunnày cho phép bạn tạo những số(giả) ngẫu nhiên. Chúng ta sẽsử dụng mô-đun này trong vídụ đầu tiên:

Hãy phân tích từng dònglệnh. Bốn dòng đầu tiên là chúthích. Chúng ta đã nói về chúngtrong bài trước. Dòng thứ nămthông báo cho Python sử dụngmô-đun random. Chúng ta bắtbuộc phải khai báo một cáchtường minh cho Python để nạp.

Dòng thứ bảy tạo một vònglặp 'for' để hiển thị 14 số ngẫunhiên. Dòng thứ tám sử dụnghàm randint() để xuất ra mộtsố nguyên ngẫu nhiên giữa 1và 10. Chú ý rằng chúng taphải nói cho Python biết hàmđược gọi từ mô-đun nào. Chúngta làm việc đó (trong trườnghợp này) bằng cách viếtrandom.randint. Vì sao chúngta phải tạo mô-đun? Hãy nghĩlà nếu tất cả các hàm đều được

nạp thẳng vàoPython, khôngnhững Pythonsẽ phình to lênvà chậm chạpmà còn làmcho việc sửalỗi trở nên khókhăn. Khi sửdụng mô-đun, chúng ta có thểchia nhỏ các câu lệnh vào cácnhóm theo những mục đích sửdụng nhất định. Ví dụ: nếu bạnkhông cần sử dụng chức năngcủa cơ sở dữ liệu, bạn khôngcần phải biết là có một mô-đuncho SQLite. Mặc dù vậy, khi bạncần nó thì nó luôn có sẵn.(Chúng ta sẽ sử dụng mô-đuncơ sở dữ liệu trong loạt bài viếtnày.)

Một khi bạn bắt đầu lập trìnhPython, có lẽ bạn sẽ viết nhữngmô-đun cho riêng bạn để có thểtiện sử dụng lại mà không cầngõ lại những đoạn mã đó. Nếubạn cần thay đổi cái gì trongcụm mã đó, bạn có thể làm màkhông ảnh hưởng gì mấy tớichương trình chính của mình.Tuy nhiên có một vài hạn chế ở

đây, chúng ta sẽ đề cập đếnđiều này sau. Bây giờ, khichúng ta đã sử dụng câu lệnh'import random' trước đó,chúng ta ra lệnh cho Pythoncho phép sử dụng tất cả cáchàm có trong mô-đun random.Nếu chỉ cần sử dụng riêng hàmrandint(), chúng ta có thể thayđổi câu lệnh nạp mô-đunthành:from random import randint

Bây giờ khi gọi hàm, chúngta không cần sử dụng phần'random.'. Đoạn mã ở trên sẽthay đổi thành:from random import randint# print 14 random integersfor cntr in range(1, 15) :

print randint(1, 10)

#=======================================# random_example. py# Module example using the random module#=======================================import random# print 14 random integersfor cntr in range(1, 15) :

print random. randint(1, 10)

Page 13: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 1 3 Mục lục ^

Phiên bản RCLẬP TRÌNH PYTHON - PHẦN 3

Hàm

Vừa rồi, chúng ta đã nạp mô-đun random và sử dụng hàmrandint(). Một hàm là một đoạnmã được viết để có thể đượcgọi, thường là nhiều lần, dễdàng bảo trì và giúp chúng tatránh khỏi việc phải gõ đi gõ lạimột đoạn lệnh nào đó nhiềulần. Khi bạn phải viết cùng mộtđoạn mã nào đó nhiều lần trongchương trình của mình thì đoạnmã đó nên được viết thành mộthàm. Hai ví dụ đơn giản sauđây sẽ nói lên sự tiện lợi củaviệc sử dụng hàm. Giả sử chúngta cần lấy hai số, cộng chúng,nhân chúng và cuối cùng là trừchúng với nhau, sau đó là hiệncác số và kết quả mỗi lần. Khókhăn hơn, chúng ta phải làmviệc đó 3 lần với 3 cặp số. Đoạnmã sau có thể là một ví dụ:

Không những phải gõ rấtnhiều, nó có thể dẫn tới lỗi, cóthể khi gõ hay khi thay đổi mộtcái gì đó sau này. Thay vào đó,chúng ta sẽ tạo một hàm tên là'DoTwo' sẽ nhận hai số và tínhtoán, hiển thị kết quả mỗi lần.Chúng ta bắt đầu bằng cách sửdụng từ khoá 'def' (ý chỉ rằngchúng ta đang định nghĩa một

hàm). Sau 'def',chúng ta viết tên củahàm và một danhsách các tham số(nếu có) trong ngoặcđơn. Dòng định nghĩakết thúc bởi một dấuhai chấm (:). Đoạnmã trong hàm phảiđược thụt lề. Và dướiđây là ví dụ thứ 2:

Như đã thấy,chúng ta chỉ phải gõ8 dòng thay vì 12 dòng. Nếuchúng ta cần thay đổi gì đótrong hàm, chúng ta có thể làmviệc đó mà không làm ảnhhưởng nhiều tới chương trìnhchính. Để gọi một hàm, chúngta sử dụng tên hàm và sau đólà các tham số.

Sau đây là một ví dụ khác vềhàm. Với những yêu cầu sau:

Chúngta cầntạo mộtchươngtrìnhhiển thịmộtdanhsách của

những mặt hàng được địnhdạng một cách gọn gàng. Giốngnhư hình ở trang sau.

Với giá của từng mặt hàngvà giá tổng cộng được tính theođồng đô-la và xu. Độ rộng củabảng có thể thay đổi được. Giátrị bên trái và bên phải cũng cóthể thay đổi được. Chúng ta sửdụng 3 hàm để làm việc này.Một hàm hiển thị dòng đầu và

dòng cuối, một hàm hiển thịcác mặt hàng cũng như dòngtổng cộng và cuối cùng là mộthàm để hiển thị dòng phâncách. May mắn là Python có thểgiải quyết nhiều vấn đề mộtcách dễ dàng. Nếu bạn nhớ lại,chúng ta đã từng xuất ra mộtchuỗi nhân với 4 và nhận đượcbốn bản sao của chuỗi đó.Chúng ta có thể sử dụng điềuđó trong trường hợp này. Để

#silly exampleprint ' Adding the two numbers %d and %d = %d ' % ( 1, 2, 1+2)print ' Multiplying the two numbers %d and %d = %d ' % ( 1, 2, 1*2)print ' Subtracting the two numbers %d and %d = %d ' % ( 1, 2, 1-2)print ' \n'print ' Adding the two numbers %d and %d = %d ' % ( 1, 4, 1+4)print ' Multiplying the two numbers %d and %d = %d ' % ( 1, 4, 1*4)print ' Subtracting the two numbers %d and %d = %d ' % ( 1, 4, 1-4)print ' \n'print ' Adding the two numbers %d and %d = %d ' % ( 10, 5, 10+5)print ' Multiplying the two numbers %d and %d = %d ' % ( 10, 5, 10*5)print ' Subtracting the two numbers %d and %d = %d ' % ( 10, 5, 10-5)print ' \n'

#silly example 2. . . still silly, but betterdef DoTwo(num1, num2) :

print ' Adding the two numbers %d and %d = %d ' % (num1, num2, num1+num2)print ' Multiplying the two numbers %d and %d = %d ' % (num1, num2, num1*num2)print ' Subtracting the two numbers %d and %d = %d ' % (num1, num2, num1-num2)print ' \n'

DoTwo(1, 2)DoTwo(1, 4)DoTwo(10, 5)

Page 14: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 1 4 Mục lục ^

Phiên bản RC

hiển thị dòng đầu hoặc cuối,chúng ta có thể lấy độ rộng, trừđi 2 cho hai dấu '+' và sử dụng"'=' * (width -2)" (width là độrộng của bảng). Để đơn giảnhơn, chúng ta sử dụng thay thếbiến để cho tất cả phần tử vàomột dòng. Dòng lệnh sẽ códạng : '%s%s%s' % ('+', ('=' *(width-2)), '+'). Giờ chúng ta cóthể cho hàm xuất ra trực tiếpnhưng chúng ta sẽ sử dụng từkhoá "return" để trả chuỗi đượctạo về dòng lệnh gọi hàm.Chúng ta đặt tên hàm là'TopOrBottom' và đoạn mã chohàm sẽ là:def TopOrBottom(width) :

# width is total widthof returned line

return ' %s%s%s' %( ' +' , ( ' =' * (width-2) ) , ' +' )

Chúng ta có thể bỏ chú thíchnhưng sẽ tốt hơn là chỉ ra thamsố 'width' là gì. Để gọi hàm,chúng ta viết 'printTopOrBottom(40)' hoặc thay 40

bằng một độ rộng khác. Nhưvậy đã có một hàm để hiển thịhai dòng cần thiết. Chúng ta cóthể tạo một hàm khác chochuỗi phân cách sử dụng cáchviết tương tự... HOẶC, chúng tacó thể thay đổi hàm trên bằngcách thêm vào tham số chỉ ra kítự nằm giữa các dấu cộng. Thửlàm điều đó và vẫn gọi hàm làTopOrBottom.defTopOrBottom(character, width) :

# width is total widthof returned line

# character is thecharacter to be placedbetween the ' +' characters

return ' %s%s%s' %( ' +' , ( character * (width-2) ) , ' +' )

Giờ chúng ta có thể thấy sựcần thiết của chú thích. Nhớrằng chúng ta đang trả lại chuỗitạo được do vậy cần phải có cáigì đó để nhận nó khi gọi hàm.Thay vì gán vào một chuỗikhác, chúng ta sẽ hiển thị nó ra

luôn. Đây là dòng gọihàm.printTopOrBottom( ' =' , 40)

Chúng ta khôngnhững giải quyết

được ba dòng mà chúng ta cònrút ngắn được số hàm cần dùngtừ 3 xuống 2. Chỉ còn lại mỗiphần giữa của bảng nữa.

Hãy gọi hàm tiếp theo là'Fmt'. Chúng ta sẽ truyền chonó bốn tham số:val1 - Giá trị bên tráileftbit - Độ rộng của "cột" bêntráival2 - Giá trị bên phải (là mộtsố dấu chấm động)rightbit - Độ rộng của "cột"bên phải

Việc đầu tiên phải làm làđịnh dạng dữ liệu ở phía bênphải. Do phải định dạng dữ liệuđể hiển thị theo đô-la và xu,chúng ta có thể dùng một hàmđặc biệt (cho sự thay thế biến)để hiển thị giá trị dấu chấmđộng với n số thập phân saudấu phân cách. Câu lệnh sẽ là'%2.f'. Chúng ta sẽ gán nó chobiến 'part2'. Câu lệnh đầy đủ sẽlà: 'part2 = '%2.f' % val2'. Tacũng có thể sử dụng một sốhàm mặc định của Python đểxử lí chuỗi là ljust và rjust. Ljustsẽ canh trái chuỗi, thêm vàophía bên phải với một kí tự nàođó bạn chỉ định. Rjust cũnghoạt động như vậy nhưng phần

thêm vào sẽ ở phía bên trái.Giờ thử xem việc sử dụng cáchtrộn biến vào một chuỗi lớn vàtrả về cho phần câu lệnh gọi.Sau đây là dòng tiếp theo.return ' %s%s%s%s' % ( ' | ' ,val1. lj ust(leftbit - 2, ' ' ) ,part2. rj ust(rightbit - 2, '' ) , ' | ' )

Mới nhìn vào thì có vẻ trôngrất là phức tạp, nhưng thử phântích từng phần để thấy nó rấtđơn giản:Return - Chúng ta gửi chuỗitạo được về cho câu lệnh gọi.'%s%s%s%s' - Chúng ta sẽghép 4 giá trị vào chuỗi, mỗigiá trị sử dụng một %s làmphần giữ chỗ.% ( - Bắt đầu danh sách biến'| ', - Print these literalsval1. ljust((leftbit - 2), ' ' ) -Nhận biến val1, canh lề trái vớidấu cách cho (leftbit - 2) ký tự.Chúng ta trừ đi 2 cho hai kí tự '|' ở phía bên trái.part2.rjust(rightbit - 2, ' ' ) -Canh lề phải chuỗi với rightbit -2 dấu cách.' |' - kết thúc chuỗi.

Đó là tất cả những gì trongcâu lệnh trên. Trong khi kiểmtra lỗi, bạn có thể thử nghiệm

' +===============================+'' | Item 1 X. XX | '' | Item 2 X. XX | '' | -------------------------------| '' | Total X. XX | '' +===============================+'

LẬP TRÌNH PYTHON - PHẦN 3

Page 15: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 1 5 Mục lục ^

Phiên bản RC

với nó. Thực sự, hàm Fmt chỉ cóhai dòng ngoài dòng dịch nghĩavà chú thích. Chúng ta có thểgọi nó như sau.print Fmt( ' Item1' , 30, item1, 10)

Cũng như trên chúng ta cóthể gán giá trị trả lại vào mộtchuỗi nhưng chúng ta chỉ hiểnthị nó ra. Ở câu lệnh trênchúng ta gửi 30 cho độ rộngbên trái và 10 cho độ rộng bênphải. Tổng cộng sẽ bằng giá trị40 chúng ta gửi choTopOrBottom trước đó. Giờhãy bật trình soạn thảo và gõvào đoạn mã sau.

Lưu đoạn mã thành tập tin'pprint1.py' và chạy nó. Bạnsẽ nhận được.

Mặc dù đây chỉ là một thídụ đơn giản nhưng từ đó bạncó thể hiểu tại sao và làmthế nào sử dụng hàm. Giờthử mở rộng một chút và họcthêm về danh sách. Bạn cònnhớ về phần 2 khi chúng tanói về danh sách? Có mộtđiều mà tôi đã không nói vớicác bạn là một danh sách cóthể chứa mọi thứ, kể cảnhững danh sách. Thử định

nghĩa một danh sách mới trongchương trình với tên là 'itms'như sau:itms =[ [ ' Soda' , 1. 45] , [ ' Candy' , . 75] ,[ ' Bread' , 1. 95] , [ ' Milk' , 2. 59] ]

Nếu chúng ta muốn truyxuất một danh sách bìnhthường, chúng ta sẽ dùng printitms[0]. Tuy vậy, cái chúng tanhận được sẽ là ['Soda', 1.45],không phải là thứ chúng ta cầntrong trường hợp này. Chúng ta

muốn truy xuấttất cả các phầntử trong danhsách đầu tiên.Chúng ta sẽdùng 'printitms[0][0]' đểcó 'Soda' và[0][1] để cóphần giá bán,chính là 1.45.Giờ chúng ta có 4 mặt hàng đãmua và chúng ta muốn sử dụngthông tin đó để hiển thị ra.Chúng ta chỉ cần thay đổi phần

cuối của chương trình. Lưu lạichương trình trước đó thành'pprint2.py', rồi ghi chú haidòng định nghĩa itemx và thêmvào danh sách mà chúng ta vừa

#pprint1. py#Example of semi-useful functions

def TopOrBottom(character, width) :# width is total width of returned linereturn ' %s%s%s' % ( ' +' , ( character * (width-2) ) , ' +' )

def Fmt(val1, leftbit, val2, rightbit) :# prints two values padded with spaces# val1 is thing to print on left, val2 is thing to print on right# leftbit is width of left portion, rightbit is width of right portionpart2 = ' %. 2f' % val2return ' %s%s%s%s' % ( ' | ' , val1. lj ust(leftbit-2, ' ' ) , part2. rj ust(rightbit-2, ' ' ) , ' | ' )

# Define the prices of each itemitem1 = 3. 00item2 = 15. 00# Now print everything out. . .print TopOrBottom( ' =' , 40)print Fmt( ' Item 1' , 30, item1, 10)print Fmt( ' Item 2' , 30, item2, 10)print TopOrBottom( ' -' , 40)print Fmt( ' Total' , 30, item1+item2, 10)print TopOrBottom( ' =' , 40)

+======================================+

| Item 1 3. 00 |

| Item 2 15. 00 |

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

| Total 18. 00 |

+======================================+

LẬP TRÌNH PYTHON - PHẦN 3

Page 16: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 1 6 Mục lục ^

Phiên bản RC

đề cập. Đoạn mã sẽ thành.#item1 = 3. 00#item2 = 15. 00itms =[ [ ' Soda' , 1. 45] , [ ' Candy' , . 75] ,[ ' Bread' , 1. 95] , [ ' Milk' , 2. 59] ]

Tiếp theo, xoá bỏ hết cácdòng lệnh gọi Fmt(). Sau đóthêm vào các dòng sau (nhữngcái có chú thích #NEW LINE ởcuối) để cho đoạn mã của bạntrông giống như.

Tôi đặt một biến đếm chovòng lặp sẽ chạy suốt danhsách. Nhớ rằng tôi vừa thêmvào một biến tên là total.Chúng ta gán cho biến total là0 trước khi sử dụng vòng lặp.Khi hiển thị từng mặt hàng đãbán, chúng ta cộng thêm giávào total. Cuối cùng, chúng tahiển thị total ngay sau dòngphân cách. Lưu chương trình lạivà chạy nó. Bạn sẽ nhận đượckết quả tương tự như hình phíadưới.

Nếu bạn muốn hơn nữa, bạncó thể thêm một dòng chophần thuế. Giống như đã xử lýdòng total nhưng thay vào đósử dụng (total * .086) thay chophần giá.

printFmt( ' Tax: ' , 30, total*. 086, 10)

Bạn cũng có thểthêm nhiều phần tửvào danh sách và xemchương trình chạy thếnào.

Đó là tất cả nhữnggì tôi muốn nói tronglần này. Lần tới, chúng ta sẽ tậptrung vào lớp của Python. Chúcvui!

Greg Walters là chủ củaRainyDay Solutions, LLC, mộtcông ty tư vấn ở Aurora, Colorado,là lập trình viên từ năm 1 972. Ôngthích nấu nướng, đi bộ đường dài,nghe nhạc và dành thời gian chogia đình.

itms = [ [ ' Soda' , 1. 45] , [ ' Candy' , . 75] , [ ' Bread' , 1. 95] , [ ' Milk' , 2. 59] ]

print TopOrBottom( ' =' , 40)

total = 0 #NEW LINEfor cntr in range(0, 4) : #NEW LINE

print Fmt(itms[ cntr] [ 0] , 30, itms[ cntr] [ 1] , 10) #NEW LINEtotal += itms[ cntr] [ 1] #NEW LINE

print TopOrBottom( ' -' , 40)print Fmt( ' Total' , 30, total, 10) #CHANGED LINEprint TopOrBottom( ' =' , 40)

+======================================+| Soda 1. 45 || Candy 0. 75 || Bread 1. 95 || Milk 2. 59 |+--------------------------------------+| Total 6. 74 |+======================================+

LẬP TRÌNH PYTHON - PHẦN 3

Page 17: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 1 7 Mục lục ^

Phiên bản RC

LÀM TH� NÀOViết bởi Greg Walters

L�p trình Python — Ph�n 4

L ần trước tôi đã hứa vớicác bạn là kì này chúngta sẽ thảo luận về lớp.Vì thế, chúng ta sẽ tập

trung vào nó. Lớp là gì và nó cólợi ích như thế nào?

Lớp là một cách thức tạo nênđối tượng. Một đối tượng chỉđơn giản là một cách thể hiệncác thuộc tính và hành vi theomột nhóm. Điều này nghe có vẻkhó hiểu nhưng tôi sẽ giải thíchcụ thể cho các bạn. Suy nghĩthế này, một đối tượng là cáchthức mô hình hóa cái gì đótrong thực tế. Lớp là phươngpháp dùng để thực hiện điềuđó. Ví dụ, chúng ta có ba conchó ở nhà: Beagle, Lab và mộtcon lai Shepherd/Heeler xanhcủa Đức. Cả ba đều là chónhưng chúng khác nhau. Chúngcó những đặc điểm chungnhưng cũng có những điểmriêng biệt. Ví dụ, Beagle thìthấp, mập mạp, màu nâu vàhung dữ. Lab thì vừa vừa, màuđen và rất hiền hòa. Con laiShepherd/Heeler thì cao, ốm,màu đen và hơi ngốc nghếch.Dễ dàng nhận thấy là một số

thuộc tính thì rõ ràng. Thấp/vừavừa/cao là những thuộc tính vềchiều cao. Hung dữ, hiền hòavà ngốc nghếch là những thuộctính về tính tình. Trên khía cạnhhành vi, chúng ta có thể có: ăn,ngủ, chơi và nhiều hành độngkhác.

Cả ba con đều thuộc về lớpDog (chó). Trở lại các thuộc tínhchúng ta đã dùng để miêu tảphía trên, ta có các dạng như:Dog.Name (tên), Dog.Height(chiều cao), Dog.Build (ốm,mập, …) và Dog.Color (màu).Chúng ta cũng có các hành vinhư: Dog.Bark (sủa), Dog.Eat(ăn), Dog. Sleep (ngủ), …

Như tôi đã đề cập, mỗi conchó thuộc mỗi giống khác nhau.

Mỗi giống chó sẽ là một lớp concủa lớp Dog. Mối quan hệ đượcbiểu diễn như sơ đồ sau:

/--BeagleDog ---| -- Lab

\--Shepherd/Heeler

Mỗi lớp con thừa kế tất cảcác thuộc tính của lớp Dog. Vìthế, nếu chúng ta tạo một thểhiện của Beagle, nó sẽ có tất cảcác thuộc tính từ lớp cha Dog.Beagle = Dog( )Beagle. Name = ' Archie'Beagle. Height = ' Short'Beagle. Build = ' Chubby'Beagle. Color = ' Brown'

Mọi thứ đã bắt đầu rõ rànghơn rồi đúng không? Hãy tạomột lớp Dog hoàn chỉnh (phía

trên). Chúng ta sẽ bắt đầu vớitừ khóa “class” và tên của lớp.

Trước khi giải thích kĩ hơnvào đoạn mã, chú ý hàm chúngta đã định nghĩa ở đây. Hàm__init__ (hai dấu gạch dưới +'init' + hai dấu gạch dưới) làhàm khởi tạo đối với mọi lớp.Ngay khi lớp được gọi trong mãthì đoạn chương trình này sẽđược chạy. Trong trường hợpnày, chúng ta phải thiết lậpmột số tham số để tạo một vàithông tin cơ bản về lớp củachúng ta, bao gồm: tên, màu,chiều cao, tầm vóc, tính tình,tuổi và một cặp biến Hungry(đói) và Tired (mệt). Chúng tasẽ trở lại trong lát nữa. Bây giờhãy thêm vào một số dòng mã.

class Dog( ) :def __init__(self, dogname, dogcolor, dogheight, dogbuild, dogmood, dogage) :

#here we setup the attributes of our dogself. name = dognameself. color = dogcolorself. height = dogheightself. build = dogbuildself. mood = dogmoodself. age = dogageself. Hungry = Falseself. Tired = False

Page 18: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 1 8 Mục lục ^

Phiên bản RCLẬP TRÌNH PYTHON - PHẦN 4Beagle = Dog( ' Archie' ,' Brown' , ' Short' , ' Chubby' ,' Grumpy' , 12)print Beagle. nameprint Beagle. colorprint Beagle. moodprint Beagle. Hungry

Đây là những dòng mãkhông dự tính trước (sẽ làm) vànằm bên ngoài lớp của chúngta. Đoạn mã sử dụng lớp Dog.Dòng đầu tiên tạo một thể hiệncủa lớp Dog tên là Beagle. Nóđược gọi là một thực thể cụ thể.Khi viết những dòng mã trên,chúng ta cũng đã truyền vàomột vài thông tin cho thực thểcủa lớp này, như là tên củaBeagle, màu và nhiều thứ khácnữa. Bốn dòng tiếp theo đơngiản chỉ truy vấn thông tin từđối tượng Beagle và lấy nhữngthông tin trả về đó. Lúc nàychúng ta cần viết thêm vàidòng mã nữa. Thêm vào nhữngdòng mã trên góc bên phải củatrang này vào lớp ngay sauhàm __init__.

Bây giờ chúng ta có thể gọiBeagle.Eat() và Beagle.Sleep().Hãy thêm vào một phương thứcnữa, Bark. Đoạn mã được trìnhbày bên phải đây.

Cái này tôi viết cho nó linh

hoạt hơn. Tùy thuộc vào tínhtình của con chó, tiếng sủa sẽthay đổi. Toàn bộ đoạn mã đầyđủ được trình bày ở trang kếtiếp.

Khi chúng ta chạy thì sẽđược kết quả như sau:My name is ArchieMy color is BrownMy mood is GrumpyI am hungry = FalseSniff Sniff. . . Not HungryYum Yum. . . Num NumGRRRRR. . . Woof Woof

Hiện tại, chúng ta đã có đượccon Beagle già hung dữ. Tuynhiên, như tôi đã nói ngay từđầu là có đến 3 con chó. Bởi vìchúng ta đã viết mã cho lớpDog một cách cẩn thận rồi, tấtcả những gì chúng ta cần làm làtạo thêm hai thể hiện nữa cholớp.Lab = Dog( ' Nina' , ' Black' ,' Medium' , ' Heavy' , ' LaidBack' , 7)Heeler = Dog( ' Bear' , ' Black' ,' Tall' , ' Skinny' , ' Crazy' , 9)print ' My Name is %s'%Lab. nameprint ' My color is %s'%Lab. colorprint ' My Mood is %s'%Lab. moodprint ' I am hungry = %s'%Lab. Hungry

Lab. Bark( )Heeler. Bark( )

Chú ý rằng tôi đã tạo ra cácthể hiện cho cả hai con chótrước khi tôi thực hiện câu lệnhprint. Điều này không làm nảysinh vấn đề gì cả bởi vì tôi đãđịnh nghĩa thể hiện trước khigọi bất kì phương thức nào. Đâylà toàn bộ những gì xuất ramàn hình của chương trình cholớp Dog.My name is ArchieMy color is BrownMy mood is GrumpyI am hungry = FalseSniff Sniff. . . Not Hungry

Yum Yum. . . Num NumGRRRRR. . . Woof WoofMy Name is NinaMy color is BlackMy Mood is Laid BackI am hungry = FalseYawn. . . ok. . . WoofBark Bark Bark Bark Bark BarkBark

Giờ đây bạn đã có nhữngkiến thức cơ bản nhất, bài tậpvề nhà dành cho bạn là mởrộng lớp Dog đã viết thêmnhiều phương thức hơn, ví dụnhư là Play(chơi) hayEncounterStrangeDog(chạmtrán một con chó lạ), đại loạinhư vậy.

def Eat(self) :if self. Hungry:

print ' Yum Yum. . . Num Num'self. Hungry = False

else:print ' Sniff Sniff. . . Not Hungry'

def Sleep(self) :print ' ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'self. Tired = False

def Bark(self) :if self. mood == ' Grumpy' :

print ' GRRRRR. . . Woof Woof'elif self. mood == ' Laid Back' :

print ' Yawn. . . ok. . . Woof'elif self. mood == ' Crazy' :

print ' Bark Bark Bark Bark Bark Bark Bark'else:

print ' Woof Woof'

Page 19: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 1 9 Mục lục ^

Phiên bản RC

Lần tới, chúng ta sẽ bắt đầuthảo luận về GUI hay còn gọi làlập trình giao diện người dùngđồ họa. Chúng ta sẽ sử dụngBoa Constructor để thực hiện.

class Dog( ) :def __init__(self, dogname, dogcolor, dogheight, dogbuild, dogmood, dogage) :

#here we setup the attributes of our dogself. name = dognameself. color = dogcolorself. height = dogheightself. build = dogbuildself. mood = dogmoodself. age = dogageself. Hungry = Falseself. Tired = False

def Eat(self) :if self. Hungry:

print ' Yum Yum. . . Num Num'self. Hungry = False

else:print ' Sniff Sniff. . . Not Hungry'

def Sleep(self) :print ' ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'self. Tired = False

def Bark(self) :if self. mood == ' Grumpy' :

print ' GRRRRR. . . Woof Woof'elif self. mood == ' Laid Back' :

print ' Yawn. . . ok. . . Woof'elif self. mood == ' Crazy' :

print ' Bark Bark Bark Bark Bark Bark Bark'else:

print ' Woof Woof'

Beagle = Dog( ' Archie' , ' Brown' , ' Short' , ' Chubby' , ' Grumpy' , 12)print ' My name is %s' % Beagle. nameprint ' My color is %s' % Beagle. colorprint ' My mood is %s' % Beagle. moodprint ' I am hungry = %s' % Beagle. HungryBeagle. Eat( )Beagle. Hungry = TrueBeagle. Eat( )Beagle. Bark( )

Greg Walters là chủ củaRainyDay Solutions, LLC, mộtcông ty tư vấn ở Aurora, Colorado,là lập trình viên từ năm 1 972. Ôngthích nấu nướng, đi bộ đường dài,nghe nhạc và dành thời gian chogia đình.

LẬP TRÌNH PYTHON - PHẦN 4

Page 20: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 20 Mục lục ^

Phiên bản RC

LÀM TH� NÀOViết bởi Greg Walters

L�p trình Python — Ph�n 5N ếu bạn cũng như tôi,bạn sẽ ghét phần đầutiên của việc cài đặtnày. Tôi ghét nó khi

tác giả nào đó nói với tôi rằngtôi phải đọc thật tỉ mỉ mỗi từtrong sách/chương/bài viết củahọ, bởi vì tôi chỉ biết rằng nó sẽlà một thứ làm cho tôi ngái ngủ- thậm chí tôi biết nó tốt chochính tôi, và cuối cùng tôi sẽlàm điều đó bằng bất cứ cáchnào.

Hãy cân nhắc đến những gìbạn đã được cảnh báo. Hãy đọcnhững thứ nhàm chán sau đâythật cẩn thận. Chúng ta sẽ sớmtận hưởng những điều thú vị,nhưng chúng ta cần thiết lậpmột vài bước cơ sở trước khi cóthể thực sự nói về việc lậptrình.

Đầu tiên, bạn cần cài đặtBoa Constructor và wxPython.Dùng Synaptic và chọn cả haiwxPython, Boa Constructor. Mộtkhi đã cài đặt, bạn có thể tìmBoa ởApplication|Programming|BoaConstructor. Hãy tìm và khởi

chạy nó đi. Một khi ứng dụngbắt đầu, bạn sẽ thấy ba cửa sổkhác nhau (hoặc các khung):một ở trên và hai ở phía dưới.Bạn có lẽ phải định dạng lại vàdi chuyển chúng một ít, sao chotrông giống như sau:

Khung trên cùng được gọi làkhung công cụ. Khung phía dướibên trái là khung kiểm tra, vàkhung bên phải là khung soạnthảo. Trên khung công cụ,chúng ta có một số thẻ tab(New, Containers/Layout, v.v..)chúng sẽ cho phép bạn tạo dựán mới, thêm các khung vàocác dự án hiện có, và thêm cácđiều khiển khác nhau vào cáckhung cho ứng dụng của bạn.Khung kiểm tra sẽ trở nên rấtquan trọng khi chúng ta thêm

các điều khiển vào ứng dụng.Khung soạn thảo sẽ cho phépchúng ta thêm đoạn mã, lưucác dự án, và nhiều hơn thế. Trởlại với khung công cụ, hãy nhìnvào mỗi tab – bắt đầu với tab“New”. Trong khi có quá nhiềutùy chọn ở đó, chúng ta sẽ chỉnói về hai trong số chúng.Chúng là nút thứ 5 và 6 từ tráiqua: wx.App và wx.Frame.wx.App cho phép chúng ta tạoứng dụng hoàn chỉnh có sẵn haitệp tin. Một là tệp tin khung vàcòn lại là tệp tin ứng dụng. Đâylà phương pháp tôi thích dùng.wx.Frame được dùng để thêmnhiều khung vào ứng dụng củachúng ta và/hoặc tạo một ứngdụng độc lập từ một tệp tinnguồn đơn lẻ. Chúng ta sẽ bànvề điều này sau.

Bây giờ hãy nhìn vào thẻContainers/Layout. Nhiều thứthú vị ở đây. Một thứ bạn sẽdùng nhiều là wx.Panel (đầutiên bên trái) và các tùy chọnsắp xếp (vị trí 2, 3, 4, 5 và 6 từphải qua). Trong thẻ BasicControls bạn sẽ thấy nhữngđiều khiển như văn bản tĩnh

(nhãn), các ô nhập liệu, các ôduyệt, các nút radio, và nhiềuhơn. Dưới thẻ Buttons, bạn sẽthấy các hình thức khác nhaucủa nút. Thẻ List có dữ liệudạng bảng và các ô danh sáchkhác. Chuyển đến thẻ Utilities,chúng ta sẽ tìm thấy bộ đếmthời gian và bộ thiết kế trìnhđơn.

Đây là một số điều cần nhớtrước khi chúng ta sẵn sàng choứng dụng đầu tiên. Có một vàilỗi trong phiên bản Linux. Mộtlà một vài điều khiển sẽ khôngcho phép bạn di chuyển chúngtrong chế độ thiết kế. Dùng<Ctrl> + Phím mũi tên để dichuyển hoặc thay đổi vị trí cácđiều khiển của bạn. Một lỗikhác bạn sẽ tìm thấy khi thửlàm những bài hướng dẫn vớiBoa Constructor, là khi đặt mộtbảng điều khiển, nó hơi khó đểnhìn thấy. Hãy tìm các ô nhỏ(tôi sẽ chỉ chúng cho bạn sớmthôi). bạn có thể dùng thẻ Objstrên khung kiểm tra và chọn nó.

Được rồi, chúng ta đi tiếp.Phía dưới tab “New” của khung

Page 21: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 21 Mục lục ^

Phiên bản RC

công cụ, chọn wx.App (nút thứ5 từ trái sang). Nó sẽ tạo haitab mới trong khung soạn thảo:một được đặt tên là “*(App1)*”,hai là “*(Frame1)*”. Có vẻ điênrồ nhưng điều quan trọng đầutiên chúng ta sẽ làm là lưu haitệp tin mới này, bắt đầu với tệpFrame1. Nút lưu là nút thứ 5 từtrái qua trong khung soạn thảo.Khung “Save as” sẽ hiện mộtcửa sổ hỏi bạn nơi bạn muốnlưu tệp tin và bạn muốn đặt tênnó là gì. Tạo một thư mục trongthư mục chính của bạn tên làGuiTests, và lưu tệp với tên“Frame1.py”. Chú ý tên tab“*(Frame1)*” giờ là “Frame1”.(Ký hiệu "*(" nói rằng tệp tin đócần được lưu.). Bây giờ làmtương tự với tab App1. Bây giờhãy quan sát một số nút trênthanh công cụ của khung soạnthảo. Những cái quan trọng làsao lưu (phím thứ 5 từ trái qua)và thực thi (mũi tên màu vàng,thứ 7 từ trái qua. Nếu bạn đangtrong một tab khung (ví dụFrame1) bạn sẽ cần phải biếtmột vài nút phụ. Đó là nútDesigner (thiết kế)

Nó là một thứ quan trọng.Nó cho phép chúng ta thiết kếkhung giao diện GUI – thứ màchúng ta sẽ làm lúc này. Khi

bạn nhấn vào nó bạn sẽ thấymột khung trống hiện lên.

Đây là một khung trống đểbạn đặt bất cứ điều khiển nàobạn cần (một cách hợp lý). Điềuđầu tiên chúng ta muốn làm làđặt điều khiển wx.panel. Hầuhết mọi thứ tôi từng đọc đềunói rằng không nên đặt cácđiều khiển (ngoại trừ wx.panel)trực tiếp vào trong khung. Vìvậy, nhấn vào tabContainers/Layout trong khungcông cụ, rồi nhấn chọnwx.panel. Kế đến, chuyển đếnkhung mới hiện mà bạn đangthao tác và nhấn vào một chỗnào đó trong khung. Nếu bạnthấy giống như thế này thì bạnđã làm đúng:

Còn nhớ khi tôi cảnh báo bạnvề các lỗi chứ? Đây là mộttrong số chúng. Đừng quá lolắng. Bạn thấy 8 ô vuông màuđen nhỏ chứ? Đó chính là giớihạn của panel. Nếu bạn muốn,bạn có thể nhấn và kéo mộttrong số chúng để thay đổi kíchcỡ của panel, nhưng đối với dựán này điều chúng ta muốn làlàm cho panel chiếm toàn bộkhung. Chỉ cần co kích cỡ củakhung lại một chút. Bây giờchúng ta có một cái bảng(panel) để gắn các điều khiểnvào. Di chuyển khung bạn đanglàm việc cho tới khi bạn có thểnhìn thấy thanh công cụ củakhung soạn thảo. Hai nút mớiđã xuất hiện: một nút duyệt(Check) và một nút “X”. “X” sẽhủy bỏ các thay đổi bạn vừathực hiện.

Nút duyệt:

còn được gọi là nút “Post”. Nósẽ ghi các thay đổi vào trongtệp tin khung. Bạn vẫn phải lưutệp tin khung đó, nhưng sẽ cómột vài thứ mới trong tệp tin. Vìvậy, nhấn vào nút Post. Cũngcó một nút post trong khungkiểm tra, nhưng chúng ta sẽ đềcập sau. Bây giờ hãy lưu tệp tincủa bạn.

Trở lại chế độ thiết kế. Nhấnvào tab ‘Buttons’ trên khungcông cụ và sau đó nhấn vào nútđầu tiên bên trái, wx.Button.Sau đó gắn nó vào một nơi nàođó gần giữa khung của bạn.Bạn sẽ thấy một thứ gần giốngnhư thế này:

Chú ý rằng có 8 ô vuông nhỏxung quanh nó giống như bảngpanel. Chúng là các mốc thayđổi kích thước. Nó cũng chochúng ta thấy điều khiển nàođang được chọn. Để di chuyểnnút tới gần hơn phần trung tâm

LẬP TRÌNH PYTHON - PHẦN 5

Page 22: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 22 Mục lục ^

Phiên bản RC

của khung, giữ phím Control(Ctrl) và trong khi đang nhấn,dùng các phím mũi tên để dichuyển chúng tới nơi bạnmuốn. bây giờ, hãy nhìn vàokhung kiểm tra. Có bốn thẻ tab.Nhấn vào tab ‘Constr’. Tại đâychúng ta có thể thay đổi nhãn,tên, vị trí, kích thước và kiểudáng. Bây giờ, hãy thay đổi tên(Name) thành ‘btnShowDialog’và nhãn (Label) thành ‘ClickMe’.

Bây giờ, hãy bỏ qua tất cảcác tab còn lại và đến tab Objs.Tab này cho thấy tất cả cácđiều khiển bạn có và cấp bậcgiữa chúng. Như bạn thấy, nútnày là một con của panel1,panel1 là con của Frame1.

Bấm nút duyệt và lưu thayđổi của bạn. Trở lại thiết kế mộtlần nữa, và chú ý (giả sử bạnvẫn mở tab ‘Objs’ trong khungkiểm tra) rằng Frame1 hiệnđang được chọn. Thật tiện, bởivì chúng ta muốn thế. Trở lạitab ‘Constr’, và thay đổi tiêu đề(title) từ ‘Frame1’ thành ‘OurFirst GUI’. Duyệt và lưu lại mộtlần nữa. Bây giờ hãy chạy ứngdụng của chúng ta. Nhấn vàonút Run màu vàng trên khungsoạn thảo.

Nhấn vào nút bao nhiêu lầnbạn muốn, nhưng sẽ chẳng cógì xảy ra. Tại sao? À, chúng tađã không bảo nút đó làm bất cứđiều gì. Vì vậy, chúng ta cầnthiết lập một sự kiện để kích

hoạt khi người dùng nhấn vàonút của chúng ta. Nhấn vào chữX góc ngoài cùng bên phải đểđóng khung đang chạy. Kế tiếp,trở lại thiết kế, chọn nút và đếntab ‘Evts’ trong khung kiểm tra.Nhấn vào ButtonEvent và sauđó nhấp đôi vào dòngwx.EVT_BUTTON vừa xuất hiện,và để ý trong cửa sổ bên dướichúng ta có một nút sự kiệnđược gọi là'OnBtnShowDialogButton'.Duyệt và lưu lại.

Trước khi chúng ta tiến xa

hơn, hãy xem chúng ta có gìtrong đoạn mã (trang tiếptheo).

Hàng đầu tiên là một chúthích bảo Boa Constructor rằngđây là một tệp tin boa. Nó đượcbỏ qua bởi chương trình biên

dịch của Python, nhưng với Boathì không. Dòng tiếp theo nhậpthư viện wxPython. Bây giờ hãychuyển tới định nghĩa lớp.Ở trên cùng là phương thức

__init_ctrls. Lưu ý chú thíchngay dưới dòng định nghĩa.Đừng chỉnh sửa mã trong phầnnày. Nếu bạn làm điều đó, bạnsẽ gặp rắc rối đấy. Bất cứ thứ gìtrong phương thức này cầnđược bảo toàn. Trong đây, bạnsẽ tìm thấy các định nghĩa củamỗi điều khiển trong khung củachúng ta.

Kế đến, hãy chú ý hàm__init__. Tại đây, bạn có thể đặtnhững thứ liên quan tới mã khởitạo. Cuối cùng là hàmOnBtnShowDialogButton. Đâylà nơi bạn sẽ đặt mã kích hoạtkhi người dùng nhấn nút. Lưu ýcó một dòng event.Skip(). Nóimột cách đơn giản, sự kiện sẽkết thúc ngay khi nó vừa đượckích hoạt.

Bây giờ, những gì chúng tasẽ làm là gọi một hộp thôngbáo kèm theo một thông điệp.Đây là một việc làm bìnhthường đối với lập trình viêncho phép người dùng biết vềmột điều gì đó - một lỗi, hoặc

LẬP TRÌNH PYTHON - PHẦN 5

Page 23: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 23 Mục lục ^

Phiên bản RC

thông báo một quy trình đãhoàn thành. Trong trường hợpnày, chúng tôi sẽ gọi hàm dựngsẵn wx.MessageBox. Hàm nàyđược gọi với hai tham số. Đầutiên là đoạn văn bản chúng tôimuốn gửi trong hộp thông báovà hai là tiêu đề cho hộp thôngbáo. Làm dấu chú thích ở dòngevent.Skip() và đặt vào dòngsau.wx. MessageBox( ' You Clickedthe button' , ' Info' )

Lưu lại và nhấn nút Run (mũitên màu vàng). Bạn sẽ nhìnthấy một thứ như thế này:

Và khi nhấn nút bạn sẽ thấynhư thế này:

Hãy hiểu rằng đâychỉ là cách đơn giảnnhất để gọi hộpthông báo. Ngoài ra,bạn có thể thêmnhiều tham số hơn.

Dưới đây là mộtbản tóm gọn làm thếnào để thay đổi biểutượng trạng thái trênhộp thông báo (chitiết hơn vào số tới).

wx.ICON_QUESTION- Hiển thị biểu tượng câu hỏi.wx.ICON_EXCLAMATION- Hiển thị một biểu tượng

cảnh báo.wx.ICON_ERROR- Hiển thị một biểu tượng

báo lỗi.wx.ICON_INFORMATION- Hiển thị một biểu tượng

thông tinCách viết:

wx. MessageBox( ' You Clickedthe button' , ' Info' ,wx. ICON_INFORMATION)

Hoặc bất cứ biểu tượng gì bạnmuốn dùng cho phù hợp vớitình huống. Hơn nữa cũng cónhiều kiểu bố cục các nút màchúng ta sẽ nói lần tới.Vì vậy, trong khi chờ cho

tới lần tới, hãy thử với cácbộ điều khiển, cách bố tríkhác nhau và nhiều hơn thế.Chúc vui!

#Boa: Frame: Frame1import wxdef create(parent) :

return Frame1(parent)[ wxID_FRAME1, wxID_FRAME1BTNSHOWDIALOG, wxID_FRAME1PANEL1,] = [ wx. NewId( ) for _init_ctrls in range(3) ]

class Frame1(wx. Frame) :def _init_ctrls(self, prnt) :

# generated method, don' t editwx. Frame. __init__(self, id=wxID_FRAME1, name=' ' , parent=prnt,

pos=wx. Point(543, 330) , size=wx. Size(458, 253) ,style=wx. DEFAULT_FRAME_STYLE, title=u' Our First GUI' )

self. SetClientSize(wx. Size(458, 253) )self. panel1 = wx. Panel(id=wxID_FRAME1PANEL1, name=' panel1' , parent=self,

pos=wx. Point(0, 0) , size=wx. Size(458, 253) ,style=wx. TAB_TRAVERSAL)

self. btnShowDialog = wx. Button(id=wxID_FRAME1BTNSHOWDIALOG,label=u' Click Me' , name=u' btnShowDialog' , parent=self. panel1,pos=wx. Point(185, 99) , size=wx. Size(85, 32) , style=0)

self. btnShowDialog. Bind(wx. EVT_BUTTON, self. OnBtnShowDialogButton,id=wxID_FRAME1BTNSHOWDIALOG)

def __init__(self, parent) :self. _init_ctrls(parent)

def OnBtnShowDialogButton(self, event) :event. Skip( )

Greg Walters là chủ củaRainyDay Solutions, LLC, mộtcông ty tư vấn ở Aurora, Colorado,là lập trình viên từ năm 1 972. Ôngthích nấu nướng, đi bộ đường dài,nghe nhạc và dành thời gian chogia đình.

LẬP TRÌNH PYTHON - PHẦN 5

Page 24: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 24 Mục lục ^

Phiên bản RC

Tôi hy vọng bạn đã cónhững trải nghiệm thúvị với Boa Constructorkể từ lần gặp đầu tiên.

Chúng ta sẽ bắt đầu mộtchương trình đơn giản với mộtcửa sổ và cho phép chúng tanhấn vào một nút bấm để làmxuất hiện một cửa sổ khác. Lầntrước là một bảng thông báo.Lần này, chúng ta sẽ tạo mộtcửa sổ hoàn toàn độc lập. Điềunày có thể rất hữu ích khi thiếtkế một ứng dụng có chứa nhiềucửa sổ hoặc khung. Giờ thìchúng ta đi thôi...

Khởi động Boa Constructorvà đóng tất cả các tab trongkhung soạn thảo trừ tab Shellvà Explorer bằng tổ hợp phímCtrl + W. Điều này bảo đảmchúng ta bắt đầu hoàn toàn từcon số 0. Bây giờ, hãy tạo mộtdự án mới bằng cách nhấn vàonút wx.App (tham khảo bài viếttrước).

Trước khi làm bất kỳ điều gì,hãy lưu Frame1 với tên"FrameMain.py" và App1 vớitên "GUI2.py". Đây là điều quan

trọng. Sau khi chọn thẻ GUI2,chuyển qua khung công cụ vàthêm một khung khác vào dựán bằng cách nhấn nútwx.Frame (nằm kế nút wx.App).Vẫn trong thẻ GUI2, đảm bảorằng thẻ Application hiển thịđồng thời cả hai khung dưới cộtModule. Giờ trở lại khung mớitạo và lưu lại với tên"FrameSecond.py".

Kế tiếp, mở FrameMain trongchế độ thiết kế. Thêm wx.Panelvào khung. Chỉnh kích thướcsao cho nó chiếm toàn bộkhung. Sau đó, chúng ta sẽthay đổi một vài thuộc tính,điều mà chúng đã không làm ởkỳ trước. Trong khung kiểm tra,chọn Frame1 trong thẻ Objs rồitrong thẻ Constr, sửa tên Titlethành "Main Frame" và tênName thành "FrameMain".Chúng ta sẽ bàn một chút vềquy ước đặt tên sau. Hãy thiếtlập kích thước 400x340 bằngcách nhấp vào hộp kiểm Size.Nó sẽ thả xuống hai tùy chọnchiều cao và chiều rộng. Chiềucao (Height) là 340 và chiềurộng (Width) là 400.

Bây giờ hãy nhấn vào thẻProps. Nhấn vào thuộc tínhCentered và chọn wx.BOTH.Nhấn vào nút duyệt và lưu lại.Bây giờ chạy ứng dụng của bạnbằng cách nhấn vào nút mũitên màu vàng. Ứng dụng củachúng ta sẽ hiện ra ngay trungtâm màn hình với tiêu đề "MainFrame". Giờ hãy đóng nó lạibằng cách nhấn nút "X" ở bêngóc phải của ứng dụng.

Mở khung FrameMain trongchế độ thiết kế. Thêm hai nútwx.Buttons vào khung, cái ở

trên cái ở dưới và gần giữakhung. Chọn nút ở trên, đặt tênlà "btnShowNew" và đặt nhãnlà "Show the other frame" trongthẻ Constr của khung kiểm tra.Dùng tổ hợp phím Shift + mũitên để chỉnh kích thước nút saocho thấy hết nhãn nút và dùngCtrl + mũi tên để dịch chuyểnnút trở lại giữa khung. Chọn nútở dưới, đặt tên là "btnExit" vànhãn là "Exit". Duyệt, lưu rồichạy để xem sự thay đổi. Thoátứng dụng rồi trở lại khâu thiếtkế. Chúng ta sẽ thêm sự kiệnnhấn nút. Chọn nút phía trên,vào khung kiểm tra, chọn thẻEvts. Bấm vào ButtonEvent, rồinhấp đôi vào wx.EVT_BUTTON.Để ý rằng bạn sẽ có dòng"OnBtnShowNewButton" bêndưới. Kế tiếp, chọn nút btnExit.Làm điều tương tự, đảm bảo nóxuất hiện dòng"OnBtnExitButton". Duyệt vàlưu. Chuyển qua khung soạnthảo và cuộn xuống dưới cùng.

Hãy chắc rằng bạn có haiphương thức sự kiện vừa đượctạo. Dưới đây là hình minh họacho khung của chúng ta:

LÀM TH� NÀOViết bởi Greg Walters

L�p trình Python — Ph�n 6

Page 25: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 25 Mục lục ^

Phiên bản RC

Bây giờ là lúc chúng ta thiếtkế một khung cửa sổ khác. MởFrameSecond trong thiết kế.Đặt tên Name là"FrameSecond" và tên Title là"Second Frame". Đặt canh giữalà wx.BOTH. Thêm mộtwx.Button và chuyển nó vàogiữa nhưng gần sát đáy khung.Đặt tên là "btnFSExit", và nhãnlà "Exit". Thiết lập sự kiện chonó. Tiếp theo, thêm mộtwx.StaticText vào phần nửatrên của khung. Đặt tên là"stHiThere", nhãn là "Hi there...I'm the second form!", thiết lậpphông chữ là Sans, PointSize là14 và Weight là wx.BOLD. Sau

đó canh giữa dòng chữ trở lại.Bạn có thể làm điều này bằngcách bỏ chọn thuộc tínhPosition và chỉnh tọa độ X đểdịch qua trái phải, tọa độ Y đểdịch lên xuống cho tới khi vừa ý.Duyệt và lưu lại.

Chúng ta vừa kết thúc phầnthiết kế, chúng ta sẽ tạo "chấtkeo" để kết nối tất cả lại vớinhau.

Trong khung soạn thảo, nhấnvào thẻ GUI2, sau đó, nhấn vàothẻ Source bên dưới. Dưới dòngghi là "import FrameMain", hãythêm "import FrameSecond".Lưu lại thay đổi. Kế đến, chọnthẻ "FrameMain". Bên dướidòng ghi "import wx", hãy thêmmột dòng "importFrameSecond". Tiếp theo, cuộnxuống và tìm dòng ghi"def__init__(self, parent):".Thêm một dòng phía sau dòng"self._init_ctrls(parent)" với nộidung là "self.Fs =FrameSecond.FrameSecond(self)". Bây giờ dưới "defOnBtnShowNewButton(self,event):", đánh dấu chú thíchlên dòng "event.Skip()" và thêmhai dòng dưới đây:

self. Fs. Show( )self. Hide( )

Cuối cùng, dưới phương thức"OnBtnExitButton", chú thíchdòng "event.Skip()", và thêmdòng "self.Close()"

Thế chúng có nghĩa là gì?Thế này, điều đầu tiên chúng talàm là đảm bảo rằng chươngtrình nhận biết có hai khungcửa sổ trong nó. Đó là tại saochúng ta nhập cả haiFrameMain và FrameSecondtrong tập tin GUI2. Kế đếnchúng ta nhập một tham chiếuđến FrameSecond vàoFrameMain để có thể sử dụngsau này. Chúng ta đã khởi tạonó trong phương thức "_init_".Và trong sự kiện"OnBtnShowNewButton" chúngta đã bảo nó rằng khi bút đượcbấm, chúng ta muốn thấykhung thứ hai được hiện ra vàkhung thứ nhất biến mất. Cuốicùng chúng ta có một câu lệnhđể đóng chương trình khi nútExit được nhấn.

Bây giờ, hãy chuyển sangviết lệnh cho FrameSecond. Chỉmột vài thay đổi nhỏ thôi. Dướiphương thức "_init_", thêmdòng "self.parent = parent" để

tạo biến self.parent. Cuối cùngbên dưới sự kiện nhấn nútFSExitButton, chú thích dòng"event.Skip()" và thêm haidòng:self. parent. Show( )self. Hide( )

Còn nhớ chúng ta đã giấukhung đầu tiên khi khung thứhai xuất hiện không? Giờ chúngta phải làm ngược lại. Chúng tagiấu khung thứ hai đi. Cuốicùng, lưu thay đổi của bạn.

Đây là toàn bộ mã lệnh đểbạn kiểm tra lại mọi thứ (trangnày và trang kế tiếp):

Bây giờ bạn có thể chạychương trình. Nếu mọi thứ diễnra tốt đẹp, bạn có thể nhấn vàonút btnShowNew và thấy khungđầu tiên biến mất ngay khikhung thứ hai hiện ra. Nhấn nútExit trên khung thứ hai sẽ làmkhung này biến mất và khungban đầu sẽ xuất hiện trở lại.Nhấn nút Exit trên khung chínhnày sẽ kết thúc chương trình.

Tôi đã hứa với bạn là chúngta sẽ bàn về quy ước đặt tên.Hãy nhớ lại, có phải chúng tađã bàn về việc chú thích mã

LẬP TRÌNH PYTHON - PHẦN 6

Page 26: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 26 Mục lục ^

Phiên bản RC

GUI2 code:

#! /usr/bin/env python#Boa: App: BoaApp

import wx

import FrameMainimport FrameSecond

modules ={u' FrameMain' : [ 1, ' Main frame of Application' ,u' FrameMain. py' ] ,u' FrameSecond' : [ 0, ' ' , u' FrameSecond. py' ] }

class BoaApp(wx. App) :def OnInit(self) :

self. main = FrameMain. create(None)self. main. Show( )self. SetTopWindow(self. main)return True

def main( ) :application = BoaApp(0)application. MainLoop( )

if __name__ == ' __main__' :main( )

FrameMain code:

#Boa: Frame: FrameMain

import wximport FrameSecond

def create(parent) :return FrameMain(parent)

[ wxID_FRAMEMAIN, wxID_FRAMEMAINBTNEXIT,wxID_FRAMEMAINBTNSHOWNEW,wxID_FRAMEMAINPANEL1,

] = [ wx. NewId( ) for _init_ctrls in range(4) ]

class FrameMain(wx. Frame) :def _init_ctrls(self, prnt) :

# generated method, don' t editwx. Frame. __init__(self, id=wxID_FRAMEMAIN,

name=u' FrameMain' ,parent=prnt, pos=wx. Point(846, 177) ,

size=wx. Size(400, 340) ,style=wx. DEFAULT_FRAME_STYLE, title=u' Main

Frame' )self. SetClientSize(wx. Size(400, 340) )self. Center(wx. BOTH)

self. panel1 = wx. Panel(id=wxID_FRAMEMAINPANEL1,name=' panel1' ,

parent=self, pos=wx. Point(0, 0) ,size=wx. Size(400, 340) ,

style=wx. TAB_TRAVERSAL)

self. btnShowNew =wx. Button(id=wxID_FRAMEMAINBTNSHOWNEW,

label=u' Show the other frame' ,name=u' btnShowNew' ,

parent=self. panel1, pos=wx. Point(120, 103) ,size=wx. Size(168, 29) ,

style=0)self. btnShowNew. SetBackgroundColour(wx. Colour(25,

175, 23) )self. btnShowNew. Bind(wx. EVT_BUTTON,

self. OnBtnShowNewButton,id=wxID_FRAMEMAINBTNSHOWNEW)

lệnh? Vậy thì, bằng cách dùngnhững tên gọi hợp lý cho nhữngbộ điều khiển của GUI, mã lệnhcủa bạn hầu như được tự độnggiải thích. Nếu bạn chỉ để têncác bộ điều khiển như làstaticText1 hay button1 hay gìđi nữa, khi bạn tạo một khungphức tạp với rất nhiều thànhphần điều khiển, đặc biệt nếucó rất nhiều ô nhập liệu hoặc

nút bấm, thì việc đặt tên có ýnghĩa rất quan trọng. Nó có thểkhông mấy quan trọng nếu chỉcó bạn là người xem mã nguồn,nhưng để người khác có thểtiếp tục phát triển công việccủa bạn, những cái tên đúngđắn sẽ giúp họ rất nhiều. Vì thế,hãy sử dụng cách đặt tên tươngtự như sau:

LẬP TRÌNH PYTHON - PHẦN 6

Page 27: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 27 Mục lục ^

Phiên bản RC

FrameMain Code (cont. ) :self. btnExit =

wx. Button(id=wxID_FRAMEMAINBTNEXIT, label=u' Exit' ,name=u' btnExit' , parent=self. panel1,

pos=wx. Point(162, 191) ,size=wx. Size(85, 29) , style=0)

self. btnExit. SetBackgroundColour(wx. Colour(225,218, 91) )

self. btnExit. Bind(wx. EVT_BUTTON,self. OnBtnExitButton,

id=wxID_FRAMEMAINBTNEXIT)

def __init__(self, parent) :self. _init_ctrls(parent)self. Fs = FrameSecond. FrameSecond(self)

def OnBtnShowNewButton(self, event) :#event. Skip( )self. Fs. Show( )self. Hide( )

def OnBtnExitButton(self, event) :#event. Skip( )self. Close( )

FrameSecond code:#Boa: Frame: FrameSecond

import wx

def create(parent) :return FrameSecond(parent)

[ wxID_FRAMESECOND, wxID_FRAMESECONDBTNFSEXIT,wxID_FRAMESECONDPANEL1,wxID_FRAMESECONDSTATICTEXT1,

] = [ wx. NewId( ) for _init_ctrls in range(4) ]

class FrameSecond(wx. Frame) :def _init_ctrls(self, prnt) :

# generated method, don' t editwx. Frame. __init__(self, id=wxID_FRAMESECOND,

name=u' FrameSecond' ,

parent=prnt, pos=wx. Point(849, 457) ,size=wx. Size(419, 236) ,

style=wx. DEFAULT_FRAME_STYLE, title=u' SecondFrame' )

self. SetClientSize(wx. Size(419, 236) )self. Center(wx. BOTH)self. SetBackgroundStyle(wx. BG_STYLE_COLOUR)

self. panel1 = wx. Panel(id=wxID_FRAMESECONDPANEL1,name=' panel1' ,

parent=self, pos=wx. Point(0, 0) ,size=wx. Size(419, 236) ,

style=wx. TAB_TRAVERSAL)

self. btnFSExit =wx. Button(id=wxID_FRAMESECONDBTNFSEXIT, label=u' Exit' ,

name=u' btnFSExit' , parent=self. panel1,pos=wx. Point(174, 180) ,

size=wx. Size(85, 29) , style=0)self. btnFSExit. Bind(wx. EVT_BUTTON,

self. OnBtnFSExitButton,id=wxID_FRAMESECONDBTNFSEXIT)

self. staticText1 =wx. StaticText(id=wxID_FRAMESECONDSTATICTEXT1,

label=u"Hi there. . . I' m the second form! " ,name=' staticText1' ,

parent=self. panel1, pos=wx. Point(45, 49) ,size=wx. Size( 336, 23) ,

style=0)self. staticText1. SetFont(wx. Font(14, wx. SWISS,

wx. NORMAL, wx. BOLD,False, u' Sans' ) )

def __init__(self, parent) :self. _init_ctrls(parent)self. parent = parent

def OnBtnFSExitButton(self, event) :#event. Skip( )self. parent. Show( )self. Hide( )

LẬP TRÌNH PYTHON - PHẦN 6

Page 28: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 28 Mục lục ^

Phiên bản RC

Control type - Name prefixStatic text - st_Button - btn_Text Box - txt_Check Box - chk_Radio Button - rb_Frame - Frm_ or Frame_

Bạn có thể có những ý tưởngriêng về quy ước đặt tên trongquá trình trở thành lập trìnhviên và trong một vài trườnghợp, sếp hay người chủ của bạncó lẽ đã lập ra sẵn những quyước.

Lần tới, chúng ta sẽ tạm biệtlập trình giao diện đồ họa đểtập trung vào lập trình cơ sở dữliệu. Trong lúc này, hãy cài đặtpython-apsw và python-mysqldb lên máy của bạn. Bạncũng sẽ cần sqlite vàsqlitebrowser cho SQLite. Nếubạn cũng muốn trải nghiệm vớiMySql, đó là một ý tưởng khôngtồi. Tất cả đều có sẵn trongSynaptic.

Greg Walters là chủ củaRainyDay Solutions, LLC, mộtcông ty tư vấn ở Aurora, Colorado,là lập trình viên từ năm 1 972. Ôngthích nấu nướng, đi bộ đường dài,nghe nhạc và dành thời gian chogia đình.

LẬP TRÌNH PYTHON - PHẦN 6

by Richard Redeiby Richard Redei

Page 29: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 29 Mục lục ^

Phiên bản RC

LÀM TH� NÀOViết bởi Greg Walters

L�p trình Python — Ph�n 7

Xin chào các chàng traivà cô gái. Đã đến giờkể chuyện. Các bạn đãtìm một chỗ ngồi thật

thoải mái chưa? Sẵn sàng rồichứ? Thế thì chúng ta bắt đầu!

Ngày xửa ngày xưa, thế giớitràn ngập giấy. Giấy, giấy ởkhắp nơi. Người ta phải xâynhững ngôi nhà đặc biệt chochúng. Họ gọi đó là tủ hồ sơ,những chiếc hộp kim loại to lớnđó chiếm đầy hết căn phòngnày đến căn phòng nọ, từ cơquan cho đến gia đình chỉ đểchứa giấy. Trong mỗi tủ hồ sơcó những thứ gọi là túi hồ sơdùng để nhóm các giấy tờ cóliên quan lại với nhau. Nhưngsau một thời gian, chúng cũngchật cứng hoặc mục nát vì đểquá lâu hoặc được tra cứu quánhiều.

Để sử dụng đúng cáchnhững tủ hồ sơ đó, người ta cầnphải có trình độ bậc phổ thông.Phải mất cả ngày để lục tìm tấtcả những giấy tờ được xếptrong những tủ hồ sơ khácnhau. Công việc bị trì trệ rất

nhiều. Đó quả là thời khắc cựckỳ đen tối trong lịch sử loàingười.

Rồi một ngày, trên đỉnh củamột ngọn núi nào đó (tôi nghĩđó là Colorado, tôi không chắclắm), xuất hiện một cô tiên xinhđẹp. Cô khoác trên người mộtmàu xanh lấp lánh ánh bạc, vớiđôi cánh lộng lẫy và mái tóctrắng muốt, và cô chỉ caokhoảng 30 cm. Tên cô ta, dù tinhay không, là See-Quill (đọcnhư SQL). Một cái tên buồn cườiphải không? Sao cũng được,See-Quill nói rằng cô có thể giảiquyết tất cả mọi vấn đề từ giấytờ, tủ hồ sơ và thời gian, vớiđiều kiện mọi người phải tintưởng vào cô ta và máy điệntoán. Cô gọi phép màu nhiệmcủa mình là "Cơ sở dữ liệu". Cônói rằng "Cơ sở dữ liệu" có thểthay thế toàn bộ hệ thống hồ sơhiện tại. Một số người đã làmtheo và cuộc sống của họ trởnên rất hạnh phúc. Một số khácthì không, và cuộc sống của họvẫn không thay đổi, lạc lõnggiữa hàng núi giấy.

Tuy nhiên, tất cả những lờihứa hẹn của cô tiên đều kèmtheo điều kiện. Lần này, điềukiện là những ai muốn sử dụngquyền năng của See-Quill đềuphải học một ngôn ngữ mới. Nókhông quá khó để học. Thực tế,ngôn ngữ này giống với cái mọingười thường sử dụng. Chỉ cómột chút khác biệt trong cáchnói, và cần phải suy nghĩ thậtkỹ trước khi nói để sử dụngquyền nãng của See-Quill.

Một ngày nọ, một chàngthanh niên tò mò tên là Userđến gặp See-Quill. Anh ta rấtcảm kích trước vẻ đẹp của côvà nói "See-Quill ơi, làm ơn chỉcho tôi cách sử dụng quyềnnăng của cô đi." See-Quill đáplại rằng cô sẽ chỉ cho anh ta.

Cô nói với chàng trai: "Trướctiên, anh phải biết thông tin củaanh được sắp xếp như thế nào.Vui lòng cho em xem nhữnggiấy tờ của anh."

Vì còn trẻ, User chỉ có mộtvài tờ giấy. See-Quill nói với anhta: "User này, hiện tại anh có

thể sống với những xấp giấy vànhững tập hồ sơ. Tuy nhiên, emcó thể tiên đoán rằng một ngàykia, anh sẽ có nhiều giấy đếnnỗi nếu xếp chồng chúng lênnhau thì chúng sẽ cao gấp 15lần anh đó. Nhưng anh đừng lovì đã có quyền năng của emmà."

Thế là User và See-Quill làmviệc cùng nhau và họ đã tạonên một thứ gọi là "cơ sở dữliệu" (một thuật ngữ kỹ thuậtcủa thần tiên) và User sống rấthạnh phúc cho đến cuối đời.Hết truyện.

Dĩ nhiên, truyện kể khônghoàn toàn đúng thực tế. Tuynhiên, việc sử dụng cơ sở dữliệu và SQL có thể làm cho cuộcsống chúng ta dễ dàng hơn.Trong bài này chúng ta sẽ tìmhiểu một vài truy vấn SQL đơngiản và làm thế nào để áp dụngvào chương trình. Một vài ngườicó thể nghĩ rằng đây có thểkhông phải là một cách "đúng"hay là cách "tốt nhất" nhưng đólà một cách hợp lý. Vậy thì hãy

Page 30: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 30 Mục lục ^

Phiên bản RCLẬP TRÌNH PYTHON - PHẦN 7bắt đầu.

Cơ sở dữ liệu giống như cáitủ hồ sơ trong câu chuyện vừarồi. Bảng dữ liệu giống như tậphồ sơ. Một bản ghi độc lậptrong bảng giống như một tờgiấy. Mỗi mẫu thông tin đượcgọi là trường. Tất cả được sắpxếp rất gọn gàng phải không?Bạn dùng câu lệnh SQL để thaotác với dữ liệu. SQL nghĩa làngôn ngữ truy vấn có cấu trúc(Structured Query Language)và được thiết kế để đơn giảnhóa cách sử dụng cơ sở dữ liệu.Nhưng trong thực tế, nó có thểtrở nên rất phức tạp. Chúng tasẽ giữ mức độ đơn giản tronggiai đoạn này.

Khi bắt đầu xây dựng bất cứdự án nào, chúng ta cần tạomột sơ đồ. Hãy lấy ví dụ vềphiếu công thức nấu ăn, đó làmột ví dụ hay bởi vì chúng tasẽ tạo nên một cơ sở dữ liệu vềcông thức. Ở nhà tôi, công thứcnằm ở nhiều dạng: tấm cạc 3x5in, tờ giấy 8x10 in, khăn ăn vớicông thức in trên đó, trang tạpchí và kể cả những dạng lạ lùngkhác. Chúng có thể được tìmthấy trên sách, hộp, tủ, v.v.. Tuynhiên, chúng đều có một điểm

chung: định dạng của chúng.Trong hầu hết trường hợp,chúng ta thấy phần đầu là tênmón ăn và có thể là số khẩuphần ăn và xuất xứ món ăn.Phần thân chứa danh sáchnguyên liệu và phần cuối chứacách nấu, trình tự nấu, thời giannấu, v.v.. Chúng ta sẽ sử dụngđịnh dạng chung này như mộtkiểu mẫu cho cơ sở dữ liệu củachúng ta. Chúng ta sẽ chia dựán này thành hai phần: hômnay chúng ta sẽ tạo cơ sở dữliệu và lần tới sẽ tạo ứng dụngđể có thể tra cứu và cập nhậtdữ liệu.

Lấy một ví dụ. Giả sử chúngta có một công thức món ăn ởphía bên phải.

Hãy chú ý trình tự mà chúngta vừa bàn. Khi chúng ta thiếtkế cơ sở dữ liệu, chúng ta cóthể dự kiến chứa tất cả thôngtin của công thức chỉ trong mộtbản ghi. Tuy nhiên, nó trở nênnặng nề và khó khăn trongquản lý sau này. Thay vì vậy,chúng ta sẽ sử dụng phiếu nấuăn như một kiểu mẫu. Một bảngsẽ chứa phần đầu, tức là thôngtin tổng quát của món ăn, bảngkhác sẽ lưu phần thân, nguyênliệu, và một bảng khác nữa để

chứa phần cuối, cách làmmón ăn.

Đảm bảo bạn đã cài đặtSQLite và APSW. SQLite làmột bộ máy quản lý cơ sởdữ liệu nhỏ hoạt độngkhông cần phải có mộtmáy chủ cơ sở dữ liệuriêng, rất phù hợp với dựán nhỏ của chúng ta. Mọithứ bạn học được ở đây cóthể áp dụng cho hệ thốngcơ sở dữ liệu lớn hơn nhưMySQL, ... Một điểm haynữa ở SQLite là nó sử dụnggiới hạn các kiểu dữ liệu.Đó là kiểu Text, Numeric,Blob và Integer PrimaryKey. Như các bạn đã biết,kiểu Text cho phép chứabất kỳ thông tin văn bảnnào. Những nguyên liệu,chỉ dẫn, tựa món ăn đều ởdạng Text, kể cả đôi khichúng chứa những con số.Kiểu Numeric cho phépchứa những con số, có thểlà số nguyên, số thực haydấu chấm động. Blob làkiểu dữ liệu nhị phân, ví dụnhư hình ảnh. IntegerPrimary Key hơi đặc biệtmột tí. SQLite dùng nó đểghi tự động một giá trị số

Spanish Rice

Serves: 4Source: Greg WaltersIngredients:1 cup parboiled Rice (uncooked)1 pound Hamburger2 cups Water1 8 oz can Tomato Sauce1 small Onion chopped1 clove Garlic chopped1 tablespoon Ground Cumin1 teaspoon Ground OreganoSalt and Pepper to tasteSalsa to tasteInstructions:Brown hamburger.Add all other ingredients.Bring to boil.Stir, lower to simmer and cover.Cook for 20 minutes.Do not look, do not touch.Stir and serve.

Page 31: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 31 Mục lục ^

Phiên bản RC

nguyên duy nhất. Điều này sẽquan trọng trong chốc lát nữa.

APSW là từ viết tắt của chữAnother Python SQLiteWrapper, nó cho phép kết nốidễ dàng với SQLite. Bây giờ hãyxem xét một vài cách tạo truyvấn SQL.

Để lấy thông tin từ cơ sở dữliệu, bạn sẽ dùng câu lệnhSELECT. Cú pháp là:SELECT [ what] FROM [ whichtable(s) ] WHERE [ Constraints]

Vậy, nếu chúng ta muốn lấytoàn bộ các trường trong bảngRecipes (công thức), chúng tasẽ viết:SELECT * FROM Recipes

Nếu bạn muốn lấy dữ liệutheo khóa chính của nó, bạnphải biết giá trị của khóa chínhđó (pkID, trong ví dụ này) vàthêm lệnh WHERE vào câulệnh, như thế này:SELECT * FROM Recipes WHEREpkID = 2

Cũng đơn giản, phải không?Cứ như là ngôn ngữ hàng ngàyấy. Bây giờ, hãy giả định rằng

chúng ta chỉ muốn lấy tên củamón ăn và số khẩu phần ăn củatất cả các công thức. Dễ ợt. Tấtcả những gì chúng ta làm làthêm một danh sách các trườngvào trong câu truy vấn SELECT:SELECT name, servings FROMRecipes

Để thêm thông tin, chúng tadùng câu lệnh INSERT INTO. Cúpháp là:INSERT INTO [ table name](field list) VALUES (valuesto insert)

Vậy, để thêm một công thứcvào bảng Recipes, câu lệnh sẽlà:INSERT INTO Recipes (name,serves, source) VALUES( "Tacos" , 4, "Greg" " )

Để xóa một bản ghi, chúngta có thể dùngDELETE FROM Recipes WHEREpkID = 10

Ngoài ra cũng có câu lệnhcập nhật UPDATE, nhưng chúngta sẽ nói về nó vào một dịpkhác.

Nói thêm về SELECT

Trong trường hợp cơ sở dữliệu của chúng ta, chúng ta có 3bảng liên kết với nhau nhờ cácrecipeID trỏ về pkID trong bảngRecipes. Giả sử chúng ta muốnlấy thông tin cách nấu của mộtmón ăn. Chúng ta có thể làmnhư sau:SELECT Recipes. name,Recipes. serves,Recipes. source,Instructions. instructionsFROM Recipes LEFT JOINInstructions ON (Recipes. pkID= Instructions. recipeID)WHERE Recipes. pkID = 1

Tuy nhiên, câu lệnh trên quádài và dư thừa. Chúng ta có thểdùng những từ thay thế (alias)như sau:SELECT r. name, r. servings,r. source, i. instructionsFROM Recipes r LEFT JOINInstructions i ON (r. pkID =i. recipeID)WHERE r. pkID = 1

Nó ngắn hơn mà vẫn dễ đọc.Bây giờ chúng ta sẽ viết mộtchương trình nhỏ để tạo cơ sởdữ liệu, các bảng và nhập mộtvài dữ liệu đơn giản vào bảngđể có thể làm việc. Trong tương

lai, chúng ta có thể tích hợp nóvào trong chương trình đầy đủ,nhưng trong ví dụ này, chúngta sẽ tách thành chương trìnhriêng lẻ. Đây là chương trình chỉchạy một lần, nếu bạn chạy lầnthứ hai, bạn sẽ gặp lỗi khi tạobảng. Ngoài ra, chúng ta có thểđặt nó vào giữa cặp lệnh"try...catch", nhưng chúng ta sẽlàm điều đó vào một lúc khác.

Chúng ta hãy bắt đầu bằngviệc nhập mô-đun APSW.import apsw

Điều tiếp theo chúng ta cầnlàm là tạo kết nối tới cơ sở dữliệu. Nó sẽ được đặt ở cùng thưmục với ứng dụng của ta. Khichúng ta tạo kết nối, SQLite sẽtự động dò tìm xem cơ sở dữliệu đã tồn tại hay chưa. Nếuchưa, nó sẽ tạo cho chúng ta.Một khi chúng ta có kết nối,chúng ta cần cái gọi là con trỏ.Cái đó sẽ tạo một cơ chế đểchúng ta thao tác với cơ sở dữliệu. Vì vậy nên nhớ rằng chúngta cần một kết nối và một contrỏ. Chúng được tạo ra như sau:# Opening/creating databaseconnection=apsw. Connection( " cookbook. db3" )cursor=connection. cursor( )

LẬP TRÌNH PYTHON - PHẦN 7

Page 32: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 32 Mục lục ^

Phiên bản RC

Vậy là chúng ta đã có mộtkết nối và một con trỏ. Bây giờchúng ta cần tạo ra bảng. Sẽ có3 bảng trong ứng dụng. Một đểchứa thông tin chung của mónăn, một chứa toàn bộ hướngdẫn nấu nướng và một chứathành phần nguyên liệu. Chúngta không thể làm điều đó chỉtrong một bảng phải không? Cóchứ, dĩ nhiên là được, nhưngbạn thấy đó, nó sẽ làm chobảng rất phức tạp và chứanhiều thông tin trùng lắp.

Chúng ta có thể xem xét cấutrúc bảng như thế này. Mỗi cộtlà một bảng:

Mỗi bảng có một trường gọilà pkID. Đó là khóa chính và làgiá trị có tính duy nhất trongbảng. Điều này là quan trọng vìdữ liệu trong bảng không baogiờ được phép có 2 dòng giốnghệt nhau. Nó có kiểu số nguyênvà được cấp phát tự động bởibộ máy cơ sở dữ liệu. Bạn cóthể làm mà không cần đến nókhông? Có thể, nhưng bạn dễnhầm lẫn dẫn đến trùng lặp sốid. Trong trường hợp của bảngRecipes, chúng ta sẽ dùng consố này để biết cách nấu nào vànguyên liệu nào sẽ kết hợp với

món ăn đó.Đầu tiên, chúng ta sẽ đặt

thông tin tên, nguồn gốc vàkhẩu phần ăn vào bảngRecipes. pkID được cấp phát tựđộng. Nếu như chúng ta đặtdòng thông tin đầu tiên vàobảng, hệ thống sẽ cấp phát chopkID giá trị là 1. Chúng ta sẽ sửdụng giá trị này để liên kết cácthông tin liên quan ở các bảngkhác. Bảng Instructions cũngđơn giản. Nó chỉ chứa một vănbản dài các hướng dẫn, chỉ sốpkID của riêng nó và một chỉ sốtrỏ về một công thức trongbảng Recipes. Bảng Ingredientsphức tạp hơn một tí ở chỗchúng ta có mỗi bản ghi chomỗi nguyên liệu cũng như chỉsố pkID của riêng nó và chỉ sốtrỏ về món ăn trong bảngRecipes.

Vậy để tạo bảng Recipes,chúng ta định nghĩa một biến

kiểu chuỗi tên là sql và gán câulệnh tạo bảng cho nó:sql = ' CREATE TABLE Recipes(pkID INTEGER PRIMARY KEY,name TEXT, serves TEXT,source TEXT) '

Kế đến chúng ta yêu cầuAPSW thực hiện câu lệnh:cursor. execute(sql)

Bây giờ chúng ta tạo nhữngbảng khác:sql = ' CREATE TABLEInstructions (pkID INTEGERPRIMARY KEY, instructionsTEXT, recipeID NUMERIC) '

cursor. execute(sql)

sql = ' CREATE TABLEIngredients (pkID INTEGERPRIMARY KEY, ingredientsTEXT, recipeID NUMERIC) '

cursor. execute(sql)

Một khi tất cả các bảng đã

được tạo, chúng ta sử dụng câulệnh INSERT INTO để nhập từngkhối dữ liệu vào mỗi bảng.

Nhớ rằng pkID được cấp pháttự động, vì thế chúng ta khôngtính đến nó trong danh sáchcác trường trong câu lệnhinsert. Và vì chúng ta sẽ xácđịnh tên của trường nên chúngcó thể được đặt theo bất kỳ trậttự nào, không bắt buộc phảitheo trình tự đã tạo ra trongbảng. Miễn là chúng ta nhậpđúng tên của trường, mọi thứsẽ diễn ra suông sẻ. Câu lệnhinsert vào bảng Recipes nhưsau:sql = ' INSERT INTO Recipes(name, serves, source) VALUES( " Spanish Rice" , 4, "GregWalters" ) '

cursor. execute(sql)

Kế đến chúng ta cần biết giátrị đã được gán vào pkID trong

RECIPES INSTRUCTIONS INGREDIENTS------------ ---------------------- --------------------pkID (Integer Primary Key) pkID(Integer Primary Key) pkID (Integer Primary Key)name (Text) recipeID (Integer) recipeID (Integer)source (Text) instructions (Text) ingredients (Text)serves (Text)

LẬP TRÌNH PYTHON - PHẦN 7

Page 33: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 33 Mục lục ^

Phiên bản RC

bảng Recipes. Chúng ta có thểlàm điều đó bằng câu lệnh đơngiản sau:SELECT last_insert_rowid( )

Tuy nhiên, không thể sửdụng trực tiếp dễ dàng như vậy.Cần phải dùng một loạt các câulệnh sau:sql = "SELECTlast_insert_rowid( ) "

cursor. execute(sql)

for x in cursor. execute(sql) :lastid = x[ 0]

Tại sao lại như vậy? Chà, khichúng ta lấy dữ liệu từ APSW,nó trả về dưới dạng tuple. Đâylà điều chúng ta chưa từng đềcập đến. Giải thích ngắn gọn thìtuple giống như một danh sách(list), nhưng không thể thay đổiđược. Nhiều người hiếm dùngtuple, nhưng một số thì dùngthường xuyên; dùng hay khônglà tùy bạn. Dòng lệnh cuối cùngcó nghĩa là chúng ta muốn lấygiá trị trả về đầu tiên. Chúng tadùng vòng lặp 'for' để lấy giá trịtrong biến tuple x. Hiểu chứ?OK, chúng ta tiếp tục...

Bước tiếp theo chúng ta sẽ

tạo câu lệnh insert cho bảngInstructions:sql = ' INSERT INTOInstructions (recipeID,instructions) VALUES ( %s," Brown hamburger. Stir in allother ingredients. Bring to aboil. Stir. Lower to simmer.Cover and cook for 20 minutesor until all liquid isabsorbed. " ) ' % lastid

cursor. execute(sql)

Lưu ý rằng chúng ta đangdùng sự thay thế biến (%s) đểđưa pkID của món ăn (lastid)vào trong câu lệnh sql. Cuốicùng, chúng ta cần chèn từngnguyên liệu vào trong bảngIngredients. Tôi sẽ cho bạn xemmột ví dụ:sql = ' INSERT INTOIngredients (recipeID,ingredients) VALUES ( %s, " 1cup parboiled Rice(uncooked) " ) ' % lastid

cursor. execute(sql)

Cuối cùng, lưu tất cả lại vàchạy trong một cửa sổ dònglệnh để tạo cơ sở dữ liệu. Cũngkhông quá khó đúng không?Lần tới sẽ phức tạp hơn mộtchút đấy.

Nếu bạn muốn chép toàn bộmã nguồn, tôi đã để nó trêntrang web của tôi, bạn có thểtải về tại đây:www.thedesignatedgeek.com

Kỳ tới, chúng ta sẽ áp dụngnhững điều đã học trong suốtquá trình để tạo một giao diệnvới các trình đơn truy cập vàocác công thức. Nó cho phépxem toàn bộ các công thức dướidạng danh sách, xem một côngthức bất kỳ, tìm kiếm và thêmbớt công thức.

Tôi khuyên bạn nên dànhchút thời gian để đọc tài liệu vềlập trình SQL. Bạn sẽ thấy vui vìđiều đó.

Greg Walters là chủ củaRainyDay Solutions, LLC, mộtcông ty tư vấn ở Aurora, Colorado,là lập trình viên từ năm 1 972. Ôngthích nấu nướng, đi bộ đường dài,nghe nhạc và dành thời gian chogia đình.

LẬP TRÌNH PYTHON - PHẦN 7

Page 34: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 34 Mục lục ^

Phiên bản RC

LÀM TH� NÀOViết bởi Greg Walters

L�p trình Python — Ph�n 8Chúng ta sẽ tiếp tục lậptrình cơ sở dữ liệu(CSDL) về công thứcnấu ăn mà chúng ta đã

làm ở phần 7. Đây sẽ là một bàidài, với nhiều dòng lệnh vì vậyhãy "giữ vững tay chèo" vàđừng vội nản chí nhé. Chúng tađã tạo CSDL. Bây giờ chúng tamuốn hiển thị phần nội dung,thêm vào hay bớt đi. Vậy chúngta làm điều đó như thế nào?Chúng ta sẽ bắt đầu với mộtứng dụng chạy trong cửa sổdòng lệnh, vì thế chúng ta cầntạo ra một trình đơn (menu).Chúng ta cũng sẽ tạo một lớpchứa các hàm thực thi CSDL.Hãy bắt đầu bằng một đoạn mãnhư ở cột bên phải.

Bây giờ chúng ta sẽ bố cụctrình đơn. Trình đơn sẽ là mộtvòng lặp hiển thị danh sách cáclựa chọn mà người dùng có thểyêu cầu. Chúng ta dùng dònglặp while. Viết hàm Menu giốngđoạn mã ở cột bên phải phíadưới.

Kế đến, chúng ta hoàn thànhtrình đơn bằng một cấu trúc

if|elif|else, xem ví dụ mẫu ở đầutrang kế.

Hãy nhìn lại hàm tạo trìnhđơn của chúng ta. Chúng ta bắtđầu bằng việc in những mệnhlệnh mà người dùng có thể yêucầu. Chúng ta đặt biến loop làTrue và dùng hàm while để tiếptục lặp cho đến khi loop bằngFalse. Chúng ta dùng lệnhraw_input() để chờ người dùngđưa ra một lựa chọn và khối cấutrúc if để xử lý yêu cầu ngườidùng. Trước khi chúng ta chạythử chương trình, chúng ta cầntạo một hàm __init__ trong lớp.def __init__(seft) :

pass

Giờ thì lưu chương trình lạitại nơi mà bạn đã tạo CSDL vàchạy nó. Bạn sẽ thấy điềutương tự như khung bên phảitrang sau.

Nó chỉ đơn giản hiện lêntrình đơn hết lần này đến lầnkhác, cho đến khi bạn nhập "0"

#! /usr/bin/python#------------------------------------------------------# Cookbook. py# Created for Beginning Programming Using Python #8# and Full Circle Magazine#------------------------------------------------------import apswimport stringimport webbrowser

class Cookbook( ) :def __init__(self) :

pass

def Menu( ) :cbk = Cookbook( ) # Initialize the class

Menu( )

def Menu( ) :cbk = Cookbook( ) # Initialize the classloop = Truewhile loop == True:

print' ==================================================='

print ' RECIPE DATABASE'print

' ==================================================='print ' 1 - Show All Recipes'print ' 2 - Search for a recipe'print ' 3 - Show a Recipe'print ' 4 - Delete a recipe'print ' 5 - Add a recipe'print ' 6 - Print a recipe'print ' 0 - Exit'print

' ==================================================='response = raw_input( ' Enter a selection -> ' )

Page 35: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 35 Mục lục ^

Phiên bản RCLẬP TRÌNH PYTHON - PHẦN 8

thì nó sẽ in câu "Goodbye" vàthoát. Đến đây, chúng ta có thểbắt đầu viết các hàm trong lớpCookbook. Chúng ta sẽ cần mộthàm để hiển thị tất cả thông tincó trong bảng Recipes, mộthàm cho phép bạn tìm kiếmcông thức, một hàm để xóacông thức, một hàm để thêmcông thức và một hàm để incông thức từ một máy in mặcđịnh. Hàm PrintAllRecipeskhông cần bất cứ tham số nàokhác ngoại trừ tham số (self),tương tự cho hàmSearchforRecipe và hàmEnterNew. HàmPrintSingleRecipe, DeleteRecipevà PrintOut đều cần biết côngthức nào để xử lý, vậy chúng

cần một tham số, ta gọi nó là"which". Hãy dùng lệnh pass đểkết thúc mỗi hàm. Bên tronglớp Cookbook, tạo ra các hàm:def PrintAllRecipes(self) :

passdef SearchForRecipe(self) :

passdefPrintSingleRecipe(self, which):

passdef DeleteRecipe(self, which) :

passdef EnterNew(self) :

passdef PrintOut(self, which) :

pass

Đối với một số mục trongtrình đơn, chúng ta muốn in ra

danh sách tất cả các công thứctrong bảng Recipes để ngườidùng có thể dò tìm trong danhsách. Những mục chọn đó cóthể là 1, 3, 4 và 6. Vậy, hãy sửađổi hàm menu các mục đó,thay lệnh pass bằngcbk.PrintAllRecipes(). Các bạncó thể tham khảo đoạn mãchỉnh sửa ở trang sau.

Một điều cần làm nữa là thiếtlập hàm __init__. Thay thế đoạnmã với những dòng sau:def __init__(self) :

global connectionglobal cursorself. totalcount = 0

connection=apsw. Connection( " cookbook. db3" )

cursor=connection. cursor( )

Đầu tiên, chúng ta tạo haibiến toàn cục cho kết nối và

con trỏ. Chúng ta có thể truyxuất chúng ở bất kỳ đâu tronglớp cookbook. Kế đến, chúng tatạo một biến tên self.totalcountđể đếm số lượng công thức.Chúng ta sẽ sử dụng nó sau.Cuối cùng chúng ta tạo kết nốivà con trỏ.

Bước tiếp theo là hoàn thiệnhàm PrintAllRecipes() trong lớpCookbook. Bởi vì chúng ta cóhai biến toàn cục cho kết nối vàcon trỏ nên chúng ta không cầnphải tạo lại chúng trong mỗihàm. Tiếp, chúng ta muốn hiểnthị lên màn hình những tiêu đềcông thức. Chúng ta sẽ dùng kýtự thay thế "%s" và lệnh canhlề trái để tạo khoảng cách.Chúng ta muốn nó giống nhưthế này:Item Name Serves Source---------------------------

if response == ' 1' : # Show all recipespass

elif response == ' 2' : # Search for a recipepass

elif response == ' 3' : # Show a single recipepass

elif response == ' 4' : # Delete Recipepass

elif response == ' 5' : # Add a recipepass

elif response == ' 6' : # Print a recipepass

elif response == ' 0' : # Exit the programprint ' Goodbye'loop = False

else:print ' Unrecognized command. Try again. '

/usr/bin/python -u" /home/greg/python_examples/APSW/cookbook/cookbook_stub. py"===================================================

RECIPE DATABASE===================================================1 - Show All Recipes2 - Search for a recipe3 - Show a Recipe4 - Delete a recipe5 - Add a recipe6 - Print a recipe0 - Exit===================================================Enter a selection ->

Page 36: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 36 Mục lục ^

Phiên bản RC

Cuối cùng, chúng ta cần tạocâu lệnh SQL, truy vấn CSDL vàhiển thị kết quả.

Hầu hết đã được đề cập ởbài viết trước.sql = ' SELECT * FROM Recipes'cntr = 0for x in cursor. execute(sql) :

cntr += 1print ' %s %s %s %s'

%( str(x[ 0] ) . rj ust( 5) , x[ 1] . lj ust( 30) , x[ 2] . lj ust( 20) , x[ 3] . ljust( 30) )

print ' -------------'self. totalcount = cntr

Biến cntr sẽ đếm số lượngcông thức hiển thị cho ngườidùng. Hàm của chúng ta đãxong. Khung bên phải là đoạnmã đầy đủ của hàm để bạn

tham khảo khi cần.Lưu ý rằng chúng ta đang sử

dụng kết quả kiểu tuple đượctrả về từ lệnh cursor.executecủa APSW. Chúng ta hiển thị sốpkID của mỗi công thức ở cộtItem. Điều này giúp chúng tachọn đúng công thức sau này.Khi bạn chạy chương trình, bạnsẽ thấy trình đơn, khi bạn chọnmục số 1, bạn sẽ nhận được kếtquả như hình ở đầu trang sau.

Đó là điều chúng ta muốn,ngoại trừ nếu bạn đang chạyứng dụng trong Dr.Python hoặctương tự vậy, chương trình sẽkhông có những khoảng dừng.Hãy thêm một khoảng dừng

cho đến khi người dùng nhấnmột nút để họ có thể theo dõitrong một vài giây. Trong lúc đó,hãy hiển thị tổng số công thứctừ biến mà chúng ta đã tạo ratrước đó. Hãy thêm vào dưới lựachọn 1 của trình đơn:print ' Total Recipes - %s'%cbk. totalcountprint ' ----------------------------------------------------'res = raw_input( ' Press A Key-> ' )

Chúng ta sẽ bỏ qua mục số 2(Search for a recipe) một lát vàxử lý mục số 3 (Show a singlerecipe). Hãy lưu tâm đến phầntrình đơn trước. Chúng ta sẽhiển thị danh sách các côngthức, như mục số 1, và hỏi

người dùng chọn một. Để đảmbảo không mắc lỗi vì ngườidùng nhập sai, chúng ta sẽ incâu hỏi cho người dùng (Selecta recipe =>), nếu người dùngnhập đúng, chúng ta sẽ gọihàm PrintSingleRecipe() tronglớp Cookbook với mã pkID từbảng Recipes. Nếu đầu vàokhông phải là con số, nó sẽ báolỗi ValueError, chúng ta sẽ bắtnó bằng lệnh except ValueError:như khung bên phải trang kế.

Kế tiếp, chúng ta sẽ làm việcvới hàm PrintSingleRecipe tronglớp Cookbook. Vì đã có kết nốivà con trỏ rồi nên chúng ta tạocâu truy vấn SQL. Trong trườnghợp này, chúng ta dùngsql = ' SELECT * FROM RecipesWHERE pkID = %s' %str(which)

if response == ' 1' : # Show all recipescbk. PrintAllRecipes( )

elif response == ' 2' : # Search for a recipepass

elif response == ' 3' : # Show a single recipecbk. PrintAllRecipes( )

elif response == ' 4' : # Delete Recipecbk. PrintAllRecipes( )

elif response == ' 5' : # Add a recipepass

elif response == ' 6' : # Print a recipecbk. PrintAllRecipes( )

elif response == ' 0' : # Exit the programprint ' Goodbye'loop = False

else:print ' Unrecognized command. Try again. '

def PrintAllRecipes(self) :print ' %s %s %s %s' %( ' Item' . lj ust( 5) ,

' Name' . lj ust( 30) , ' Serves' . lj ust( 20) ,' Source' . lj ust( 30) )

print ' ---------------------------------'sql = ' SELECT * FROM Recipes'cntr = 0for x in cursor. execute(sql) :

cntr += 1print ' %s %s %s %s' %( str(x[ 0] ) . rj ust( 5) ,

x[ 1] . lj ust( 30) , x[ 2] . lj ust( 20) , x[ 3] . lj ust( 30) )print ' ---------------------------------'self. totalcount = cntr

LẬP TRÌNH PYTHON - PHẦN 8

Page 37: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 37 Mục lục ^

Phiên bản RC

với which là giá trị chúng tamuốn tìm. Sau đó chúng taxuất ra màn hình (một cáchthân thiện) kết quả tuple trả vềtừ APSW. Với trường hợp này,chúng ta dùng x như là mộtbiến tuple tổng hợp, có cácthành phần với chỉ số index(nằm giữa cặp dấu ngoặcvuông). Bởi vì bố cục của bảngcó dạngpkID/name/serves/source,chúng ta có thể dùngx[0],x[1],x[2] và x[3] để biểudiễn thành phần. Sau đó, chúngta muốn chọn hết mọi nguyênliệu từ bảng Ingredients nơi màrecipeID (khóa ngoại liên kết

đến bảng Recipes) bằng vớipkID vừa mới sử dụng. Chúng tachạy vòng lặp trong kết quảtuple trả vể, in từng nguyênliệu, tiếp theo chúng ta lấy cáchnấu trong bảng Instructions nhưcách đã làm với bảngIngredients. Cuối cùng, chúngta đợi người dùng nhấn một nútđể họ có thể thấy công thứctrên màn hình. Đoạn mã mẫunằm ở trang kế.

Giờ đây chúng ta đã hoàn tấthai trên sáu hàm. Hãy xử lýhàm tìm kiếm, cũng bắt đầu từtrình đơn. Thật may, lần nàychúng ta chỉ gọi hàm tìm kiếm

trong lớp, vậy hãy thay thế lệnhpass bằng:cbk. SearchForRecipe( )

Phần còn lại là đi viết hàmtìm kiếm. Trong lớp Cookbook,thay thế nội dung trong hàmSearchForRecipe bằng đoạn mã

nằm ở trang 39.Có rất nhiều thứ ở đây. Sau

khi đã tạo kết nối và con trỏ,chúng ta hiển thị trình đơn tìmkiếm. Chúng ta sẽ cho ngườidùng 3 cách để tìm kiếm vàmột lối thoát trở về trình đơnchính. Chúng ta có thể để ngườidùng tìm một từ trong tên côngthức, một từ trong nguồn gốccông thức hoặc một từ trongdanh sách nguyên liệu. Do vậy,chúng ta không thể chỉ dùnghàm hiển thị mới vừa tạo màphải tạo một hàm hiển thị đặcthù. Hai mục đầu tiên sử dụngcâu lệnh SELECT đơn giản vớimột chút bổ sung. Chúng ta sẽsử dụng câu lệnh định tính"like". Nếu chúng ta quen sửdụng một bộ duyệt truy vấnnhư SQLite Database Browser,câu lệnh like dùng một cặp kýtự "%". Vậy để tìm một têncông thức có chứa từ "rice", câu

Enter a selection -> 1Item Name Serves Source--------------------------------------------------------------------------------------

1 Spanish Rice 4 Greg2 Pickled Pepper-Onion Relish 9 half pints Complete Guide to Home Canning

--------------------------------------------------------------------------------------===================================================

RECIPE DATABASE===================================================1 - Show All Recipes2 - Search for a recipe3 - Show a Recipe4 - Delete a recipe5 - Add a recipe6 - Print a recipe0 - Exit===================================================Enter a selection ->

try:res = int(raw_input( ' Select a Recipe -> ' ) )if res <= cbk. totalcount:

cbk. PrintSingleRecipe(res)elif res == cbk. totalcount + 1:

print ' Back To Menu. . . 'else:

print ' Unrecognized command. Returning to menu. 'except ValueError:

print ' Not a number. . . back to menu. '

LẬP TRÌNH PYTHON - PHẦN 8

Page 38: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 38 Mục lục ^

Phiên bản RC

truy vấn sẽ là:SELECT * FROM Recipes WHEREname like ' %rice%'

Tuy nhiên, vì ký tự "%" cũnglà ký tự thay thế chuỗi, chúngta sẽ dùng %%. Tồi tệ hơn nữa,chúng ta sẽ dùng ký tự thay thếđể chèn chuỗi người dùng tìmkiếm. Vì thế, chúng ta phải ghilà '%%%s%%'. Xin lỗi nếu nólàm bạn rối mù lên. Ở câu truyvấn thứ 3 còn có câu lệnh Join.Hãy quan sát kỹ hơn:sql = "SELECTr. pkid, r. name, r. serves, r. source, i. ingredients FROM Recipesr Left Join ingredients i on(r. pkid = i. recipeid) WHEREi. ingredients like ' %%%s%%'GROUP BY r. pkid" %response

Chúng ta chọn mọi thứ trongbảng Recipes và chọn nguyênliệu trong bảng Ingredients, kếtnối giữa bảng nguyên liệu vàbảng công thức dựa trên mã sốrecipeID bằng với pkID, rồi tìmkiếm nguyên liệu dựa trên câulệnh like và cuối cùng là nhómkết quả theo mã pkID để tránhtrùng lắp. Nếu bạn còn nhớ,chúng ta có hai thứ tiêu trongcông thức thứ hai (nước sốthành và tiêu), một xanh và một

đỏ. Điều đó có thể gây lẫn lộncho chúng ta. Trong trình đơn,chúng ta có dùng:searchin = raw_input( ' EnterSearch Type -> ' )if searchin ! = ' 4' :

có nghĩa là: nếu searchin (giátrị người dùng nhập vào)KHÔNG bằng 4 thì thực thi cáclựa chọn, nếu bằng 4 thì khônglàm gì cả. Lưu ý rằng tôi dùng"!=" thay vì "<>" để biểu diễnsự không bằng nhau. Mặc dùPython 2.x chấp nhận cả hai,nhưng trong Python 3.x, nó sẽbáo lỗi sai cú pháp. Chúng ta sẽbàn về những thay đổi trongPython 3.x ở một bài viết khác.Bây giờ hãy dùng "!=" để giúpbạn nhanh chóng bắt kịp vớiPython 3.x trong tương lai. Saucùng, chúng ta xuất thông tinra màn hình theo cách dễ đọccho người dùng. Hãy xem ngườidùng thấy gì ở cột bên phảitrang 40.

Bạn có thể thấy nội dungchương trình xuất ra đẹp đẽ thếnào. Bây giờ người dùng có thểquay trở lại trình đơn chính vàdùng mục thứ 3 để truy xuấtbất cứ công thức nào họ muốnxem. Kế tiếp chúng ta sẽ thêm

công thức vào CSDL. Chúng tacũng thêm một dòng vào tronghàm menu để gọi tới hàmEnterNew:cbk. EnterNew( )

Mã nguồn để thay thế chohàm EnterNew() trong lớpCookbook có thể tìm thấy ởtrang 43.

Chúng ta bắt đầu bằng việc

định nghĩa một danh sách tên"ings", có nghĩa là nguyên liệu.Sau đó chúng ta yêu cầu ngườidùng nhập vào tiêu đề, nguồngốc và số khẩu phần. Kế đếnchúng ta mở một vòng lặp,nhập từng nguyên liệu, chènvào danh sách ings. Nếu ngườidùng nhập 0, thì sẽ thoát vònglặp và tiếp tục nhập hướng dẫncách làm. Sau đó chúng ta hiểnthị nội dung công thức và yêu

def PrintSingleRecipe(self, which) :sql = ' SELECT * FROM Recipes WHERE pkID = %s' %

str(which)print

' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'for x in cursor. execute(sql) :

recipeid = x[ 0]print "Title: " + x[ 1]print "Serves: " + x[ 2]print "Source: " + x[ 3]

print' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'

sql = ' SELECT * FROM Ingredients WHERE RecipeID =%s' % recipeid

print ' Ingredient List: 'for x in cursor. execute(sql) :

print x[ 1]print ' 'print ' Instructions: 'sql = ' SELECT * FROM Instructions WHERE RecipeID

= %s' % recipeidfor x in cursor. execute(sql) :

print x[ 1]print

' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'resp = raw_input( ' Press A Key -> ' )

LẬP TRÌNH PYTHON - PHẦN 8

Page 39: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 39 Mục lục ^

Phiên bản RCdef SearchForRecipe(self) :

# print the search menuprint ' -------------------------------'print ' Search in'print ' -------------------------------'print ' 1 - Recipe Name'print ' 2 - Recipe Source'print ' 3 - Ingredients'print ' 4 - Exit'searchin = raw_input( ' Enter Search Type -> ' )if searchin ! = ' 4' :

if searchin == ' 1' :search = ' Recipe Name'

elif searchin == ' 2' :search = ' Recipe Source'

elif searchin == ' 3' :search = ' Ingredients'

parm = searchinresponse = raw_input( ' Search for what in %s (blank to exit) -> ' % search)if parm == ' 1' : # Recipe Name

sql = "SELECT * FROM Recipes WHERE name like ' %%%s%%' " %responseelif parm == ' 2' : # Recipe Source

sql = "SELECT * FROM Recipes WHERE source like ' %%%s%%' " %responseelif parm == ' 3' : # Ingredients

sql = "SELECT r. pkid, r. name, r. serves, r. source, i. ingredients FROM Recipes r Left Join Ingredients i on(r. pkid = i. recipeid) WHERE i. ingredients like ' %%%s%%' GROUP BY r. pkid" %response

try:if parm == ' 3' :

print ' %s %s %s %s %s'%( ' Item' . lj ust( 5) , ' Name' . lj ust( 30) , ' Serves' . lj ust( 20) , ' Source' . lj ust( 30) , ' Ingredient' . lj ust( 30) )

print ' --------------------------------------------------------------------------------------'else:

print ' %s %s %s %s' %( ' Item' . lj ust( 5) , ' Name' . lj ust( 30) , ' Serves' . lj ust( 20) , ' Source' . lj ust( 30) )print ' --------------------------------------------------------------------------------------'

for x in cursor. execute(sql) :if parm == ' 3' :

print ' %s %s %s %s %s'%( str(x[ 0] ) . rj ust( 5) , x[ 1] . lj ust( 30) , x[ 2] . lj ust( 20) , x[ 3] . lj ust( 30) , x[ 4] . lj ust( 30) )

else:print ' %s %s %s %s' %( str(x[ 0] ) . rj ust( 5) , x[ 1] . lj ust( 30) , x[ 3] . lj ust( 20) , x[ 2] . lj ust( 30) )

except:print ' An Error Occured'

print ' --------------------------------------------------------------------------------------'inkey = raw_input( ' Press a key' )

Page 40: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 40 Mục lục ^

Phiên bản RC

Enter a selection -> 2-------------------------------Search in-------------------------------1 - Recipe Name2 - Recipe Source3 - Ingredients4 - ExitEnter Search Type -> 1Search for what in Recipe Name (blank to exit) -> riceItem Name Serves Source--------------------------------------------------------------------------------------

1 Spanish Rice 4 Greg--------------------------------------------------------------------------------------Press a key

Easy enough. Now for the ingredient search...Enter a selection -> 2-------------------------------Search in-------------------------------1 - Recipe Name2 - Recipe Source3 - Ingredients4 - ExitEnter Search Type -> 3Search for what in Ingredients (blank to exit) -> onionItem Name Serves Source Ingredient--------------------------------------------------------------------------------------1 Spanish Rice 4 Greg 1 small Onion chopped2 Pickled Pepper-Onion Relish 9 half pints Complete Guide to Home Canning 6 cups finely chopped Onions--------------------------------------------------------------------------------------Press a key

LẬP TRÌNH PYTHON - PHẦN 8

Page 41: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 41 Mục lục ^

Phiên bản RC

cầu người dùng duyệt qua trướckhi lưu lại. Chúng ta dùng câulệnh INSERT INTO như lần trướcvà trở lại trình đơn. Một điềuchúng ta phải cẩn thận là dấunháy đơn trong dữ liệu nhậpvào. Bình thường thì nó khôngthành vấn đề trong danh sáchnguyên liệu hay cách nấu,nhưng lại có thể xảy ra đối vớitrường tiêu đề hay nguồn gốc.Chúng ta cần thêm một ký tựthoát cho bất kỳ dấu nháy đơn.Chúng ta làm điều đó bằnghàm string.replace, đó là lý dotại sao chúng ta nhập thư việnstring.

Trong hàm menu, đặt đoạnmã nằm ở bên phải phía trênvào dưới mục số 4.

Rồi trong lớp Cookbook,dùng đoạn mã ở bên phải phíadưới cho hàm DeleteRecipe().

Chúng ta sẽ nhanh chóngtìm hiểu hàm xóa. Đầu tiênchúng ta yêu cầu người dùngnhập vào mã công thức muốnxóa (trong hàm menu), vàtruyền mã pkID vào hàm xóa.Kế đến, chúng ta yêu cầu ngườidùng có chắc muốn xóa côngthức đó không. Nếu câu trả lời

là "Y" (string.upper(resp) =='Y'), thì chúng ta tạo câu lệnhsql xóa. Lưu ý rằng lúc nàychúng ta phải xóa các bản ghi ởcả ba bảng. Chúng ta có thể chỉxóa bản ghi ở bảng Recipes,nhưng dữ liệu liên kết ở 2 bảngcòn lại sẽ trở nên lạc lõng vàđiều này là không tốt. Khichúng ta xóa bản ghi ở bảngRecipes, chúng ta sử dụngtrường pkID. Trong 2 bảng kia,chúng ta dùng trường recipeID.

Cuối cùng, chúng ta xử lýhàm in công thức. Chúng ta sẽtạo một tập tin HTML thật đơngiản, mở nó bằng trình duyệtmặc định và in nó từ đó. Đó làtại sao chúng ta nhập thư việnwebbrowser. Trong hàm menu,ở mục số 6, chèn đoạn mã ởđầu trang sau.

Một lần nữa, chúng ta hiểnthị danh sách của các côngthức ra giấy, và cho phép ngườidùng chọn một cái mà họ muốnin. Chúng ta gọi hàm PrintOuttrong lớp Cookbook. Đó là đoạnmã thứ hai ở trang sau.

Chúng ta bắt đầu bằng lệnhfi = open([filename],'w') để tạora tập tin. Sau đó chúng ta lấythông tin từ bảng Recipes vàghi xuống tập tin với lệnh

fi.write. Chúng ta dùng cặp thẻ<H1></H1> cho tiêu đề, cặp<H2></H2> cho số khẩu phầnvà nguồn gốc. Kế đến chúng tadùng cặp <li></li> cho danhsách nguyên liệu, và ghi cáchlàm. Phần còn lại là những câu

truy vấn đơn giản chúng ta đãhọc. Sau cùng, chúng ta đóngtập tin lại bằng lệnh fi.close()và dùngwebbrowser([filename]) để mởtập tin vừa mới tạo. Người dùngcó thể in thông tin ra giấy từ

cbk. PrintAllRecipes( )print ' 0 - Return To Menu'try:

res = int(raw_input( ' Select a Recipe to DELETEor 0 to exit -> ' ) )

if res ! = 0:cbk. DeleteRecipe(res)

elif res == 0:print ' Back To Menu. . . '

else:print ' Unrecognized command. Returning to

menu. 'except ValueError:

print ' Not a number. . . back to menu. '

def DeleteRecipe(self, which) :resp = raw_input( ' Are You SURE you want to Delete

this record? (Y/n) -> ' )if string. upper(resp) == ' Y' :

sql = "DELETE FROM Recipes WHERE pkID = %s" %str(which)

cursor. execute(sql)sql = "DELETE FROM Instructions WHERE

recipeID = %s" % str(which)cursor. execute(sql)sql = "DELETE FROM Ingredients WHERE recipeID

= %s" % str(which)cursor. execute(sql)print "Recipe information DELETED"resp = raw_input( ' Press A Key -> ' )

else:print "Delete Aborted - Returning to menu"

LẬP TRÌNH PYTHON - PHẦN 8

Page 42: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 42 Mục lục ^

Phiên bản RC

cbk. PrintAllRecipes( )print ' 0 - Return To Menu'try:

res = int(raw_input( ' Select a Recipe to DELETE or 0 to exit -> ' ) )if res ! = 0:

cbk. PrintOut(res)elif res == 0:

print ' Back To Menu. . . 'else:

print ' Unrecognized command. Returning to menu. 'except ValueError:

print ' Not a number. . . back to menu. '

def PrintOut(self, which) :fi = open( ' recipeprint. html' , ' w' )sql = "SELECT * FROM Recipes WHERE pkID = %s" % whichfor x in cursor. execute(sql) :

RecipeName = x[ 1]RecipeSource = x[ 3]RecipeServings = x[ 2]

fi. write( " <H1>%s</H1>" % RecipeName)fi. write( " <H2>Source: %s</H2>" % RecipeSource)fi. write( " <H2>Servings: %s</H2>" % RecipeServings)fi. write( " <H3> Ingredient List: </H3>" )sql = ' SELECT * FROM Ingredients WHERE RecipeID = %s' % whichfor x in cursor. execute(sql) :

fi. write( " <li>%s</li>" % x[ 1] )fi. write( " <H3>Instructions: </H3>" )sql = ' SELECT * FROM Instructions WHERE RecipeID = %s' % whichfor x in cursor. execute(sql) :

fi. write(x[ 1] )fi. close( )webbrowser. open( ' recipeprint. html' )print "Done"

trình duyệt nếu họ muốn.Quoa! Đó là một chương

trình "vĩ đại" nhất của chúng tangày hôm nay. Nếu bạn khôngmuốn gõ lại hết tất cả hay gặpvấn đề gì đó thì bạn có thể tảimã nguồn hoàn chỉnh tại đây:

Greg Walters là chủ củaRainyDay Solutions, LLC, mộtcông ty tư vấn ở Aurora, Colorado,là lập trình viên từ năm 1 972. Ôngthích nấu nướng, đi bộ đường dài,nghe nhạc và dành thời gian chogia đình.

LẬP TRÌNH PYTHON - PHẦN 8

Page 43: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 43 Mục lục ^

Phiên bản RC

def EnterNew(self) :

ings = [ ]recipename = ' 'recipesource = ' 'recipeserves = ' 'instructions = ' 'lastid = 0

resp = raw_input( ' Enter Recipe Title (Blank line to exit) -> ' )

if resp ! = ' ' : # continue

if string. find(resp, " ' " ) :recipename = resp. replace( " ' " , " \' " )

else:recipename = resp

print "RecipeName will be %s" % recipename

resp = raw_input( ' Enter Recipe Source -> ' )

if string. find(resp, " ' " ) :recipesource = resp. replace( " ' " , " \' " )

else:recipesource = resp

resp = raw_input( ' Enter number of servings -> ' )

if string. find(resp, " ' " ) :recipeserves = resp. replace( " ' " , " \' " )

else:recipeserves = resp

print ' Now we will enter the ingredient list. '

cont = Truewhile cont == True:

ing = raw_input( ' Enter Ingredient ( " 0" to exit) -> ' )if ing ! = ' 0' :

ings. append(ing)else:

cont = False

LẬP TRÌNH PYTHON - PHẦN 8

Page 44: pyqt5.files.wordpress.com · /Mục lục ^ )*@/#L/ Những bài viết trong tạp chí này được xuất bản theo giấy phép Creative Commons Attribution-Share Alike 3.0

T�p chí Full Circle - s� ��c bi�t chuyên �� l�p trình 44 Mục lục ^

Phiên bản RC

resp = raw_input( ' Enter Instructions -> ' )instructions = resp

print ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'print "Here' s what we have so far"print "Title: %s" % recipenameprint "Source: %s" % recipesourceprint "Serves: %s" % recipeservesprint " Ingredients: "for x in ings:

print xprint " Instructions: %s" % instructionsprint ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'

resp = raw_input( "OK to save? (Y/n) -> " )

if string. upper(resp) ! = ' N' :# Write the Recipe Recordsql = ' INSERT INTO Recipes (name, serves, source) VALUES ( " %s" , " %s" , " %s" ) ' %(recipename, recipeserves,

recipesource)cursor. execute(sql)

# Get the new Recipe pkIDsql = "SELECT last_insert_rowid( ) "cursor. execute(sql)for x in cursor. execute(sql) :

lastid = x[ 0]print " last id = %s" % lastid

# Write the Ingredients Recordfor x in ings:

sql = ' INSERT INTO Ingredients (recipeID, ingredients) VALUES ( %s, " %s" ) ' % ( lastid, x)cursor. execute(sql)

# Write the Instructions recordssql = ' INSERT INTO Instructions (recipeID, instructions) VALUES( %s, " %s" ) ' %( lastid, instructions)cursor. execute(sql)

# Prompt the user that we are doneprint ' Done'

else:print ' Save aborted'

LẬP TRÌNH PYTHON - PHẦN 8