Friday, 31 October 2014

[Python] đổi thay

Hay bài học về sử dụng 2 python standard library: argparse & logging.

Khi viết chương trình Python, nếu không phải loại script chỉ dùng 1 lần, thì có hai module mà bạn sẽ luôn hối hận nếu không dùng nó ngay từ đầu. Đó là argparse để parse các tham số đầu vào của chương trình và logging để lưu lại/ hiển thị các thông tin lúc chương trình chạy.

Bởi mọi dòng code đều chỉ là tạm thời, thiết kế chương trình ban đầu cũng chỉ là tạm thời, 2 module này sẽ giúp bạn sống cùng những thứ tạm thời ấy.

1. argparse

Luôn dùng argparse khi cần parse command line argument!

Với một chương trình đơn giản, sử dụng sys.argv trực tiếp có vẻ nhanh và tiện, nhưng ngay khi bạn nhận ra mình cần thay đổi một option nào đó, mọi sự đẹp đẽ giả tạo đó bắt đầu đổ vỡ.
Nếu đã tin vào điều này, bạn có thể chuyển qua phần 2 và bỏ qua câu chuyện nhảm nhí phía dưới.

Câu chuyện nhảm nhí bắt đầu...

Một ngày, tiến sỹ X chợt nhận ra HVN, HVL và NVH là mối nguy hiểm của chương trình. Lão quyết định loại bỏ dấu vết của các yếu tố này ở khắp mọi nơi.
 

Lão viết một robot  đi tìm tất cả các phòng được chỉ định và tìm kiếm HVN, HVL và NVH để xử lý.
Chương trình có thể gọi như sau:
./loaibo.py 102 103 401 403 506 609 #danh sách các phòng cần kiểm tra 
và nếu không có argument nào được pass, chương trình sẽ tìm trên phạm vi toàn bộ tầng hiện tại (ký hiệu là ``.``)

Code python xử lý argument sẽ có dạng

if len(sys.argv) == 1:
    rooms = ['.']
else:
    rooms = sys.argv[1:]
for room in rooms:
    loai_bo_hvn(room)
    loai_bo_hvl(room)
    loai_bo_nvh(room)
 # tưởng tượng việc loại bỏ mỗi nhân tố cần thực hiện theo các phương pháp khác nhau.
mọi thứ có vẻ hợp lý. Rồi chợt đến một ngày tiến sỹ X nhận ra, chỉ có HVN là nguy hiểm. Lão  quyết định thay đổi chương trình, giờ lão muốn khi chỉ định --hvn thì chỉ có HVN là bị xử lý:
./loaibo.py --hvn
Giờ đây chương trình cần phải thay đổi, và rất... xấu:
if '--hvn' in sys.argv:
    only_hvn = True
    without_hvn = set(sys.argv).remove('--hvn')
    sys.argv = without_hvn    
...
if only_hvn:
     for room in rooms:
         loai_bo_hvn(...)
Rất xấu, rất không chính xác, và sẽ rất tệ hại khi nào cần thêm một option nữa, nếu một ngày hắn nhận ra HVL cũng nguy hiểm không kém...

Với argparse, mọi thứ luôn sẵn sàng để thay đổi.

import argparse
argp = argparse.ArgumentParser()
argp.add_argument('rooms', nargs='*', default=['.'])
argp.add_argument('--hvn', action='store_true')
args = argp.parse_args()
giờ danh sách các phòng luôn ở args.rooms, nếu không có argument nào được pass, set nó = ['.'],
nếu argument '--hvn' được pass, args.hvn sẽ = True.


5 dòng code, và mọi thứ sạch sẽ hơn và luôn sẵn sàng để thay đổi.
Chọn argparse hay không, điều đó tuỳ thuộc vào hành động của bạn. Trước khi đọc tiếp, hãy bấm vào nút play:


2. logging
Nếu muốn print, với logging module có thể set handler = sys.stdout.
Vậy
 logging = print + rất nhiều thứ khác
Setup logger chỉ mất 3 dòng, tại sao không dùng nó?

Mọi script quá 20 dòng đều cần debug, và khi chạy thật, thông tin debug không nhất hiên phải hiện ra, logging module giúp thực hiện thay đổi ấy một cách thuận tiện nhất.
Đoạn code sau ví dụ việt setup logging:
import logging
logging.basicConfig(level=logging.DEBUG)
log = logging.getLogger('org.familug')
log.info('Hello thon')

OUTPUT:
INFO:org.familug:Hello thon
Log đơn giản và tiện lợi là thế, dùng hay không tuỳ bạn.

Ở Việt Nam, có một thứ duy nhất bất biến, đó là sự thay đổi.
(Trích Understanding Vietnam của  Derek Sivers)

Tham khảo:
https://docs.python.org/2/library/logging.html
https://docs.python.org/2/library/argparse.html