Python cho người Việt

Python cho người Việt

Python - Ngôn Ngữ Lập Trình Tốt Nhất

written by vithon, on Dec 10, 2011 2:13:51 AM.

Tạp chí Linux Journal đã công bố kết quả khảo sát người đọc hàng năm của mình vào ngày 01 tháng 12 vừa qua. Theo đánh giá này, Python lại một lần nữa trong suốt ba năm liên tục được người đọc đánh giá là ngôn ngữ lập trình tốt nhất.

Thông tin chi tiết có thể được xem thêm từ nguồn Linux Journal.

Câu chuyện tối ưu hóa đoạn mã Python

written by Nguyễn Thành Nam, on Oct 26, 2011 9:21:36 AM.

Trên trang blog của Dropbox ngày hôm qua có chia sẻ kinh nghiệm của họ trong việc tối ưu hóa một đoạn mã Python ngắn.

http://tech.dropbox.com/?p=89

Kết luận của họ là:

  1. Các kỹ thuật căn bản như inline hàm (inline function), tự lặp (implicit loop), tận dụng mã C đều đúng.
  2. Cấu trúc setdict trong Python rất nhanh.
  3. Việc sử dụng biến nội bộ thay cho toàn cục mặc dù có ích, nhưng không nhiều.
  4. Ghép chuỗi (string concatenation) nhanh hơn nhiều so với định dạng chuỗi (string interpolation).

Đây là một bài chia sẻ rất hay.

Hình ảnh tại Software Freedom Day 2010

written by Nguyễn Thành Nam, on Oct 24, 2011 7:50:31 AM.

Hôm nay tự nhiên thấy trên máy có mấy tấm hình cũ ở Ngày Phần Mềm Tự Do 2010 vẫn chưa được đăng.

Năm 2010, thành viên Phan Đắc Anh Huy đã trình bày về phần mềm Vithon Forum (chính là phần mềm được sử dụng để làm Diễn đàn của nhóm PCNV). Sau đây là các tấm hình chụp hôm đó.

img20100918104740.th.jpg img20100918104748.th.jpg img20100918104833.th.jpg

Điều kiện ánh sáng tuy không được tốt nhưng cũng phần nào thể hiện được cái đầu du côn và thân hình phì lũ của Huy.

Kết quả cuộc thi Đời

written by vithon, on Oct 21, 2011 5:51:00 PM.

Cuộc thi Đời kết thúc vào tuần trước nhưng vì không có điều kiện truy cập Internet nên đến bây giờ ban tổ chức mới có thể công bố kết quả.

Cuộc thi thu hút bốn bài tham dự từ các bạn sau:

Tác giảBài tham dự
Nhâm Xuân Namlife.py
Huỳnh Hải Âubilife.py
Phan Phụng Tiếntreeoflife.py
Vũ Khuêcuocthidoi.py

Nhóm PCNV đã sử dụng một chương trình chấm giải đơn giản khác để đánh giá các bài này. Chương trình này chỉ đơn giản là tạo một ma trận MxN phần tử và yêu cầu các bài tham gia tính giá trị của các ô ngẫu nhiên tại thế một thế hệ trong tương lai.

Ở vòng đầu tiên, ma trận 1x1 được sử dụng.

G:\vithon\life>judge.py -c 1 -r 1 -n 10000 bilife.Board life.MainBoard treeoflife.Board cuocthidoi.Board
Generating random test case
Width = 1
Height = 1

0

Executing bilife.Board
Executing life.MainBoard
Executing treeoflife.Board
Executing cuocthidoi.Board

Checking for cell (0, 0)
Traceback (most recent call last):
  File "G:\vithon\life\judge.py", line 120, in <module>
    main()
  File "G:\vithon\life\judge.py", line 96, in main
    if results[module_name]['object'].get_cell(row, col):
  File "G:\vithon\life\treeoflife.py", line 160, in get_cell
    raise ValueError()
ValueError

Vì sinh ra lỗi nên mô-đun treeoflife đã bị loại.

Ở vòng hai, ma trận 2x2 được sử dụng và chỉ tính một thế hệ tương lai.

G:\vithon\life>judge.py -c 2 -r 2 -n 1 bilife.Board life.MainBoard cuocthidoi.Board
Generating random test case
Width = 2
Height = 2

1 1
0 1

Executing bilife.Board
Executing life.MainBoard
Executing cuocthidoi.Board

Checking for cell (0, 1)
*** alive count = 2, dead_count = 1
bilife is eliminated

Checking for cell (1, 0)
*** alive count = 3, dead_count = 0

Checking for cell (0, 0)
*** alive count = 2, dead_count = 1
bilife is eliminated

Checking for cell (1, 1)
*** alive count = 2, dead_count = 1
bilife is eliminated

RESULT:
[+] cuocthidoi : 0.000000 seconds
[+] life : 0.000000 seconds
[-] bilife : 0.000000 seconds

Với lần chạy này, chỉ có mô-đun bilife đưa ra kết quả sai cho trường hợp ô (0, 1). Chương trình chấm so sánh kết quả của mô-đun với kết quả của số đông. Trong trường hợp này, số đông đã đúng.

Sau hai lần chạy, chỉ còn lại hai mô-đun lifecuocthidoi.

Lần chạy thứ ba sử dụng ma trận 2x2 với một thế hệ.

G:\vithon\life>judge.py -c 2 -r 2 -n 1 life.MainBoard cuocthidoi.Board
Generating random test case
Width = 2
Height = 2

1 0
0 0

Executing life.MainBoard
Executing cuocthidoi.Board

Checking for cell (0, 0)
*** alive count = 1, dead_count = 1
life is eliminated

Checking for cell (1, 1)
*** alive count = 0, dead_count = 2

Checking for cell (1, 0)
*** alive count = 0, dead_count = 2

Checking for cell (1, 0)
*** alive count = 0, dead_count = 2

RESULT:
[-] life : 0.000000 seconds
[+] cuocthidoi : 0.000000 seconds

Với lần chạy này, life đã bị loại, và chỉ còn cuocthidoi.

Tóm lại, sau ba vòng chạy thì chỉ có mô-đun cuocthidoi đưa ra đáp án đúng. Tuy nhiên, giải này không có người chiến thắng vì mục tiêu của giải là thi về tốc độ thực thi. Khi chỉ có một đối thủ trong cuộc thi thì giải trở nên vô nghĩa. Hơn nữa, bài tham dự cuocthidoi.py đã không thực hiện đúng quy chế thứ 3 trong thể lệ tham gia nên cũng bị loại. Mặc dù không có người chiến thắng nhưng nhóm PCNV xin chúc mừng tác giả Vũ Khuê đã vượt qua các đối thủ khác trong cuộc thi.

Nói tóm lại, giải đã không đạt được mục tiêu đề ra ban đầu. Xin hẹn gặp các bạn ở các giải sau!

Cuộc thi Đời

written by vithon, on Sep 15, 2011 1:36:00 PM.

Nhóm PCNV hân hạnh tổ chức một cuộc thi nhỏ với giải thưởng lớn!

Game of Life, tạm dịch Trò chơi Đời, là một mô phỏng trạng thái các điểm trên một ma trận MxN đơn giản. Các điểm trên ma trận có trạng thái hoặc là sống, hoặc là chết. Trạng thái của một ma trận được gọi là một thế hệ. Các điểm trên ma trận ở thế hệ G sẽ tuân theo các luật sau để xác định trạng thái của chúng ở thế hệ G + 1:

  1. Nếu số lượng các điểm sống chung quanh điểm hiện tại là 3, thì điểm hiện tại sẽ sống.
  2. Nếu số lượng các điểm sống chung quanh điểm hiện tại là 2, thì điểm hiện tại sẽ tiếp tục giữ trạng thái hiện tại.
  3. Nếu số lượng các điểm sống chung quanh điểm hiện tại nhỏ hơn 2, hoặc lớn hơn 3, điểm hiện tại sẽ chết.

Cuộc thi Đời là sự tranh đua của các mã nguồn Python thực hiện việc tối ưu hóa cách thể hiện mô phỏng trên. Thể lệ của cuộc thi bao gồm:

  1. Bài tham dự gửi về địa chỉ thư admin tại vithon.org.
  2. Bài tham dự chỉ được sử dụng ngôn ngữ Python, và các thư viện chuẩn đi kèm.
  3. Bài tham dự chỉ cần hiện thực hóa lớp mẫu bên dưới bằng cách kế thừa nó và cài đặt các phương thức cần thiết.
  4. Yếu tố cơ bản để đánh giá là tốc độ chạy của chương trình.
  5. Hạn tham dự là hết ngày 15 tháng 10 năm 2011.
  6. Chỉ có một giải có trị giá tương đương 250 đô la Singapore.
  7. Quyết định của ban tổ chức là cuối cùng, xin không nhận khiếu nại.
class Board(object):
    '''Represents the Game of Life matrix.

    Each cell has at most 8 neighbors. A cell may have less than 8 neighbors.
    For example, a cell at (0, 0) would have only three neightbors (0, 1),
    (1, 0) and (1, 1).

    The cells are addressed in a row-major (row first) manner. The index starts
    from zero.

    '''

    def __init__(self, width=10, height=10):
        '''Initializes this board.

        Args:
            width (int): Number of cells in a row.
            height (int): Number of rows in this board.

        '''

        raise NotImplemented()

    def generation(self, n=1):
        '''Transform this board into next ``n`` generation(s).

        The transformation is in place similar to ``list.sort``.
        No value is returned to the caller.

        Args:
            n (int): Number of generations.

        Raises:
            ValueError: If n is smaller than 1.

        '''

        raise NotImplemented()

    def get_cell(self, row, col):
        '''Returns the state of the cell at row ``row`` and column ``col``.

        Args:
            row (int): The row, zero-indexed.
            col (int): The column, zero-indexed.

        Returns:
            True: If the cell is alive.
            False: If the cell is dead.

        '''

        raise NotImplemented()

    def set_cell(self, row, col, state):
        '''Sets a cell at row ``row`` and column ``col`` to state ``state``.

        Args:
            row (int): The row, zero-indexed.
            col (int): The column, zero-indexed.
            state (bool): Cell's state.

        '''

        raise NotImplemented()

    def get_row(self, row):
        '''Returns the states of all cells in row ``row``.

        Args:
            row (int): The row, zero-indexed.

        Returns:
            A sequence of bools.

        '''

        raise NotImplemented()

Mọi thắc mắc và thảo luận xin vui lòng gửi lên diễn đàn.

Python 3.2.2 ra đời

written by vithon, on Sep 5, 2011 2:03:00 PM.

Khoảng 10 tiếng trước, Georg Brandl đã gửi một bức thư điện tử lên hộp thư chung python-dev để công bố sự ra đời của phiên bản Python 3.2.2.

Python 3.2.2 về cơ bản là phiên bản sửa lỗi, đặc biệt là lỗi trong mô-đun urllib.request xảy ra trong 3.2.1.

Phiên bản 3.2.2 có thể được tải về từ địa chỉ http://www.python.org/download/releases/3.2.2/.

Python Tools cho Visual Studio

written by vithon, on Aug 31, 2011 4:37:43 PM.

Ngày 29 tháng 08 vừa qua, Microsoft đã tung ra phiên bản đầu tiên của phần mềm miễn phí, nguồn mở Python Tools dành cho Visual Studio.

Với công cụ này, người dùng sẽ sử dụng giao diện quen thuộc của Visual Studio để viết mã theo ngôn ngữ Python. Một số tính năng chính bao gồm trình soạn thảo, quản lý dự án, trình gỡ rối, hỗ trợ Intellisense và Refactoring, hỗ trợ IronPython lẫn CPython. Ngoài ra, nếu sử dụng Visual Studio phiên bản Ultimate, người dùng sẽ có thêm cả trình Profiler.

Công cụ Python Tools cho Visual Studio cần phiên bản Visual Studio Shell miễn phí, hoặc Visual Studio phiên bản Pro trở lên. Công cụ này không sử dụng chung với Visual Studio Express được.

Lập lịch gọi hàm với Gevent

written by Nguyễn Thành Nam, on Aug 22, 2011 2:29:00 PM.

Đôi khi chúng ta cần một cách gì đó để lập lịch gọi hàm tương tự như công cụ cron trong các hệ Unix. Nếu chúng ta may mắn đang làm việc với Gevent sẵn rồi thì hai dòng sau là một cách đơn giản để lập lịch.

def schedule(delay, func, *args, **kw_args):
    gevent.spawn_later(0, func, *args, **kw_args)
    gevent.spawn_later(delay, schedule, delay, func, *args, **kw_args)

Ý tưởng đằng sau hai dòng lệnh này là chúng ta tận dụng sẵn vòng lặp sự kiện (event loop) của Gevent để cài hàm cần được thực thi vào. Do đó, chúng ta sẽ đỡ được việc sử dụng vòng lặp với sleep. Dòng thứ hai có tác dụng như một lệnh gọi đệ quy đuôi (tail recursion), nhưng không tốn bộ nhớ ngăn xếp (stack memory).

Trong trường hợp chúng ta không sử dụng Gevent thì gói apscheduler là một lựa chọn đáng tham khảo khác. Gói này cung cấp dịch vụ lập lịch tương tự như Quartz trong thế giới Java.

Lập trình web với Python (7)

written by Nguyễn Thành Nam, on Aug 11, 2011 3:00:00 PM.

Trong bài cuối của loạt bài Lập trình web với Python, chúng ta sẽ bàn đến chuẩn WSGI (Web Server Gateway Interface).

WSGI, khác với HTTP, CGI và FCGI, không phải là chuẩn giao thức liên lạc (communication protocol) mà là chuẩn giao tiếp (standard interface) giữa ứng dụng máy chủ (server) và các khung xương (framework) hay các ứng dụng web (web application). Hình tượng hóa mà nói, WSGI nằm phía trên HTTP/CGI/FCGI và phía dưới ứng dụng thật sự. Lớp WSGI giúp lớp ứng dụng trao đổi với lớp máy chủ theo một cách khả chuyển, tức là một ứng dụng WSGI có thể chạy như nhau trên máy chủ khác nhau như Apache, NGINX, hay Lighttpd, sử dụng các giao thức khác nhau như CGI, FCGI, SCGI, hay AJP. Nói một cách khác, WSGI "che" cách liên lạc qua mạng và tạo điều kiện cho ứng dụng web tập trung vào việc xử lý các vấn đề quan trọng hơn.

Một ứng dụng WSGI là một đối tượng gọi được (callable object). Một đối tượng gọi được có thể là một hàm, một phương thức, hoặc một đối tượng có hàm call. Đối tượng gọi được này phải nhận hai tham số là environstart_response. Tham số environ là một từ điển với các khóa theo chuẩn CGI và một số khóa đặc biệt mà máy chủ WSGI có thể truyền cho ứng dụng. start_response là một đối tượng gọi được do máy chủ WSGI cung cấp cho ứng dụng để ứng dụng bắt đầu việc truyền dữ liệu cho máy chủ WSGI. start_response nhận hai tham số là dòng trạng thái trả lời (status string) và một danh sách bộ-2 (list of 2-tuple) các đầu mục (header), mỗi bộ-2 bao gồm tên và giá trị của đầu mục. Giá trị trả về của ứng dụng WSGI là một bộ khả lặp (iterable) sinh ra nội dung sẽ được máy chủ WSGI truyền lại cho máy chủ HTTP hoặc trình duyệt.

Ví dụ:

def simple_app(environ, start_response):
    """Simplest possible application object"""
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers)
    return ['Hello world!\n']

Đầu tiên, ta thiết lập chuỗi trạng thái là 200 OK, xác định đầu mục Content-typetext/plain rồi gọi start_response với các thông tin như vậy. Giá trị trả về là một danh sách với phần tử duy nhất là chuỗi Hello world!\n. Ta cũng có thể trả về chuỗi Hello world! trực tiếp mà không cần đặt nó vào trong một danh sách vì bản thân một chuỗi cũng là một đối tượng khả lặp. Tuy nhiên, làm như vậy không được khuyến khích vì khi đó máy chủ WSGI sẽ phải làm việc nhiều hơn, lặp qua từng ký tự H, e, l, l, o... thay vì lấy thẳng chuỗi trả lời.

Chúng ta sẽ viết lại ứng dụng đếm số lần truy cập như trong kỳ trước theo dạng một ứng dụng WSGI. Chúng ta sẽ tạo tập tin C:\Program Files\Apache Software Foundation\Apache2.2\fcgi-bin\hello2.py với nội dung như sau:

#!C:\Python26\python.exe
from flup.server import fcgi

class HelloApp(object):

	def __init__(self):
		self.count = 0

	def __call__(self, environ, start_response):
		self.count += 1
		start_response('200 OK', [('Content-type', 'text/plain')])
		return ['Hello WSGI World %d' % self.count]

if __name__ == "__main__":
	webapp = HelloApp()
	fcgi.WSGIServer(webapp, bindAddress=("localhost", 8888)).run()

Thực thi ứng dụng này với lệnh python hello2.py, chạy máy chủ Apache với các thiết lập đã làm trong bài viết kỳ trước, và truy cập vào địa chỉ http://localhost/fcgi-bin/hello.py thì chúng ta sẽ thấy hình như sau:

wsgi1.png

Khi làm tươi trình duyệt thì chúng ta nhận được hình sau:

wsgi2.png

So sánh ứng dụng viết theo WSGI và ứng dụng viết theo các giao thức CGI, hay FCGI ta thấy rõ rằng ứng dụng WSGI không cần quan tâm đến việc dữ liệu sẽ được truyền cho trình duyệt bằng cách nào. Ứng dụng WSGI chỉ quan tâm đến việc tạo ra dữ liệu gì và đẩy chỗ dữ liệu đó cho lớp WSGI bên dưới. Lớp này sẽ tự động thực hiện việc truyền tới trình duyệt theo cách tốt nhất có thể.

Tuy nhiên, ứng dụng WSGI cũng phải biết rõ cách hoạt động của máy chủ WSGI. Ví dụ, một ứng dụng WSGI chạy trên máy chủ WSGI theo mô hình CGI thì sẽ không thể trông chờ đến việc sử dụng lại biến toàn cục vì mỗi yêu cầu được một tiến trình riêng xử lý. Đồng thời ứng dụng WSGI cũng phải đảm bảo rằng các chuỗi trả về phải là chuỗi byte (byte string) và không được sử dụng chuỗi unicode (unicode string). Lý do là vì giao thức HTTP không hiểu unicode. Do đó, tốt nhất là ứng dụng WSGI nên gọi encode trên các chuỗi unicode để chuyển các chuỗi unicode thành các chuỗi byte trước khi đưa xuống cho máy chủ WSGI.

Một điểm hay của giao tiếp WSGI là một ứng dụng WSGI có thể gói (wrap) một ứng dụng WSGI khác bên trong. Điều này cho phép chúng ta tạo ra các ứng dụng WSGI hoạt động như các phần giữa (middleware), hoặc bộ lọc (filter).

Ví dụ:

def simple_app(environ, start_response):
    """Simplest possible application object"""
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers)
    return ['Hello world!\n']

def real_app(environ, start_response):
    r = simple_app(environ, start_response)
    return ['Tag!\n'] + r

Với đoạn mã trên, ứng dụng real_app đã gói ứng dụng simple_app và chèn vào một chuỗi Tag!\n phía trước những gì mà simple_app gửi về. Đây là một cách để tạo nên các ứng dụng web lớn từ việc ghép các ứng dụng web nhỏ lại với nhau.

Chúng ta dừng loạt bài Lập trình web với Python tại đây. Sau 7 bài viết ngắn gọn (nhưng diễn ra trong một khoảng thời gian dài), chúng ta đã xem xét qua việc cài đặt Apache, và Python, rồi các giao thức nền tảng như HTTP, CGI. Từ đó, chúng ta bàn đến các giao thức hiện đại hơn, có một số ưu điểm tốt như FCGI với ví dụ đếm số lần truy cập. Cuối cùng chúng ta dừng lại với một thảo luận ngắn về giao tiếp WSGI, là giao tiếp phổ thông nhất để viết ứng dụng web trong thế giới Python.

Tôi hy vọng sẽ gặp bạn đọc trong các bài viết khác. Để thảo luận về loạt bài này, bạn có thể sử dụng diễn đàn http://vithon.org/forum/Forum/show/7/Ung_dung_mang_web.html.

Vithon nâng cấp sử dụng Gevent

written by vithon, on Aug 1, 2011 8:25:00 AM.

Suốt thời gian qua, nhóm PCNV đã sử dụng chế độ CGI để chạy các ứng dụng web và vẫn đảm bảo được việc truy cập của các bạn quan tâm đến ngôn ngữ Python.

Tuy nhiên, để tránh các vấn đề kỹ thuật có thể phát sinh khi số lượng thành viên tăng lên, cũng như do đòi hỏi của một số tính năng trên diễn đàn, nhóm PCNV đã chuyển hai ứng dụng web là Zine và Vithon Forum qua chạy cùng Gevent, tận dụng chế độ trao đổi không đồng bộ. Việc chuyển đổi này hy vọng sẽ khiến tốc độ truy cập được cải tiến đáng kể.

Nếu các bạn gặp trục trặc trong việc truy cập vào trang PCNV và diễn đàn, thì các bạn hãy thông báo cho chúng tôi theo thông tin liên lạc ở đầu trang.