Python cho người Việt

Python cho người Việt

Entries tagged “ngôn ngữ”

Python One-Liner

written by Phạm Thị Minh Hoài, on Jan 22, 2010 11:30:00 PM.

Python One-Liner là trường phái viết Python trên một dòng. Theo đó mỗi một hành động xác định được viết bởi các lệnh cô đọng gom lại trên một dòng duy nhất. Hành động xác định không phải là những hành động quá phức tạp, nhưng cũng không quá đơn giản. Ví dụ việc trao đổi giá trị giữa hai biến có thể coi là một hành động xác định như vậy. Python cho phép thực hiện điều này trên một dòng với một lệnh duy nhất, và với tôi đó là một trong những lệnh Python đẹp nhất:

>>> a, b = b, a

Python One-Liners cũng chính là tập hợp các mẹo (trick) Python nhằm giải quyết các bài toán nhỏ một cách ngắn gọn theo phương châm “do a lot with a little.”. Điều này thường khó thực hiện ở các ngôn ngữ khác. Nhưng chúng có thể thực hiện được trong Python do đặc trưng ngôn ngữ hỗ trợ cách viết như vậy. Chẳng hạn cách dùng hàm lambda, List Comprehensions, map, filter, zip, dict, set, … đã xây dựng những đặc trưng ngôn ngữ cho phép viết các mã ngắn gọn hơn các ngôn ngữ khác.

Trong bài viết này tôi sẽ tổng hợp một số các bài toán đơn giản mà triển khai Python có thể được viết trên một dòng. Chúng là các bài toán cơ bản có liên quan đến list. Tôi hi vọng những bạn chưa biết về các công thức trong bài này sẽ tìm thấy nhiều điểm lý thú, và qua đó càng hiểu được sức mạnh và sự hấp dẫn tuyệt vời của Python. Các công thức này một số được tôi thường xuyên sử dụng, một số được sưu tầm và các bạn có thể tìm thấy ở đâu đó trên internet.

1. Làm phẳng một list

Cho một list dạng hai chiều như sau: L = \[[1,2,3],[4,5,6], [7], [8,9]\] hãy biến nó thành dạng một chiều dạng [1, 2, 3, 4, 5, 6, 7, 8, 9]. Đây là một số lời giải một dòng của bài toán này:

>>> L = [[1,2,3],[4,5,6], [7], [8,9]]
>>> sum(L, [])
>>> reduce(lambda x, y: x + y, L)
>>> list(itertools.chain(L))  #import itertools.
>>> [item for sublist in L for item in sublist]

Python cung cấp cho bạn một tập hợp phong phú các cú pháp và hàm dựng sẵn cho phép bạn giải cùng một bài toán theo nhiều cách khác nhau. Trong các lời giải trên lời giải cuối cùng là nhanh nhất và nó cũng dễ hiểu nhất. Chi tiết các lời giải trên các bạn có thể xem trên trang: Making a flat list out of list of lists in python. Hàm reduce đã bị loại bỏ kể từ Python 3000 (Suggested by Guido van Rossum), tuy nhiên vẫn được giữa lại trong thư viện functools, do vậy bạn có thể dùng:

>>> functools.reduce(lambda x, y: x + y, L)

Nếu list L không phải là hai chiều, mà có thể chứa các list con đệ quy, bạn có thể dùng hàm sau:

def flatten(seq, a = list()):
    try:                          
        for item in seq:          
            flatten(item, a)      
    except TypeError:             
        a.append(seq)             
    return a

print flatten([[1,2, [3,4], 5], 6, [7, [8, 9]]])

2. Loại bỏ các phần tử trùng nhau trong list

Hãy tạo ra một list mới chứa các phần tử không trùng nhau của L. Một số cách giải trên một dòng:

>>> L = dict.fromkeys(L).keys()  # Python 3.x trả về iterator
>>> L = list(set(L))
>>> [x for i, x in enumerate(L) if i==L.index(x)]

Với L = [5,6,1,1,1,2,2,2,3,3,3] hai lời giải trên cho kết quả [1, 2, 3, 5, 6]. Lời giải cuối cùng cho kết quả [5, 6, 1, 2, 3]. Như vậy trong một số tình huống lời giải cuối cùng tốt hơn, do nó vẫn giữa được thứ tự các phần tử như ban đầu. Tuy vậy lời giải cuối cùng chạy rất chậm. Hãy xem kết quả đo thời gian chạy của các lời giải như sau:

>>> from timeit import Timer
>>> Timer("list(set(L))", "L = range(10**4)").timeit(10)
0.030437396173560671
>>> Timer("dict.fromkeys(L).keys()", "L = range(10**4)").timeit(10)
0.027800167602894277
>>> Timer("[x for i, x in enumerate(L) if i==L.index(x)]", "L = range(10**4)").timeit(10)
25.005568798618903

Việc so sánh thời gian chạy giữa các Python One-Liner rất hay được các tác giả thực hiện. Chúng đánh giá khả năng sử dụng thực tế của mỗi công thức. Lời giải cuối cùng như các bạn thấy dù có ưu điểm song không thể dùng được khi có test xấu trên 10000 phần tử.

3. Đếm số phần tử có trong một list

Nếu chỉ đếm một phần tử thì quá đơn giản, dùng list.count là xong, nhưng nếu để đếm tần số cho nhiều item một lúc thì làm thế nào. Chẳng hạn có L = [5,6,1,1,1,2,2,2,3,3] muốn tạo ra D={5:1, 6:1, 1:3, 2:3, 3:2}.

>>> dict([(x, L.count(x)) for x in set(L)])
>>> {x: L.count(x) for x in set(L)} # dict comprehensions, có từ Python 3.x
>>> collections.Counter(L) # import collections, có từ Python 3.x

Lời giải số một tuy dài nhưng có thể chạy trên hầu hết các bản Python > 2.4. Lời giải số hai chẳng qua là từ 1 ra nhưng với cú pháp mới của Python 3.x nó dễ hiểu và đơn giản hơn. Lời giải cuối cùng đơn giản đến mức bạn chỉ cần có import collections. Module collections chứa các phương tiện cho phép bạn viết các mã Python ngắn gọn, và chạy rất nhanh. Một ví dụ khác về cách dùng Counter trong module collections, đoạn mã này cho phép đếm tần số xuất hiện của các ký tự trong một string:

>>> collections.Counter("abcabca")
Counter({'a': 3, 'c': 2, 'b': 2})

Càng về sau này các phiên bản Python càng hỗ trợ nhiều hơn các cú pháp và thư viện cho phép bạn viết các mã ngắn gọn hơn. Đây là đặc trưng của Python: “Viết ít hơn làm nhiều hơn”. Việc gia tăng hiểu biết của bạn về các thư viện là một kinh nghiệm quan trọng.

4. Chia một list thành nhiều list

Bài toán chia một list thành nhiều list có thể gặp hai yêu cầu:

  1. Chia list thành nhiều list có độ dài bằng nhau
  2. Chia list thành n list con có độ dài tương đương nhau (với khác biệt kích thước nhỏ nhất).

Vấn đề số một có thể giải quyết bằng các hàm sau:

>>> SplitInto=lambda a,n: [a[i*n:(i+1)*n] \
... for i in range(len(a) % n and len(a)/n + 1 or len(a)/n)]
>>> SplitInto(range(10), 3)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

>>> SplitInto = lambda L, n: zip(*[chain(L, repeat(None, n-1))]*n)
>>> SplitInto(range(10), 3)
<zip object at 0x01D607D8>
>>> list(SplitInto(range(10), 3))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, None, None)]

>>> SplitInto = lambda L, n: zip_longest(*[iter(L)]*n)
>>> list(SplitInto(range(10), 3))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, None, None)]
>>> SplitInto = lambda L, n: zip_longest(*[iter(L)]*n, fillvalue=-1)
>>> list(SplitInto(range(10), 3))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, -1, -1)]

>>> SplitInto= lambda L, n: [L[i:i+n] for i in range(0, len(L), n)]
>>> SplitInto(range(10), 3)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

Lời giải số 1, 4 dùng cho các phiên bản Python từ 2.3 trở đi. Hai lời giải 2, 3 sau đòi hỏi phải có lệnh from itertools import * và chỉ chạy từ Python 3.x trở đi. Chi tiết về các lời giải này các bạn có thể xem thêm: How do you split a list into evenly sized chunks in Python?

Vấn đề số 2 có thể có lời giải sau:

>>> SplitInto = lambda L, n: [L[i::n] for i in range(n)]
>>> SplitInto(range(10), 3) # SplitInto(list(range(10)), 3) với Python 3.x
[[0, 3, 6, 9], [1, 4, 7], [2, 5, 8]]

Lời giải trên là đơn giản đến mức …không cần tìm thêm các lời giải khác làm gì cho mệt. Tuy nhiên nó không chia theo đúng thứ tự. Đây là cách khác phức tạp hơn nhưng giữa nguyên được thứ tự các phần tử:

>>> SplitInto = lambda L, n: [L[int(i*1.0*len(L)/n):int((i+1)*1.0*len(L)/n)] \
... for i in range(n)]
>>> SplitInto(range(10), 3)
[[0, 1, 2], [3, 4, 5], [6, 7, 8, 9]]
>>> SplitInto(range(10), 2)
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
>>> SplitInto(range(10), 4)
[[0, 1], [2, 3, 4], [5, 6], [7, 8, 9]]

Cách viết này khá dài, nhưng giữa nguyên được thứ tự giữa các phần tử. Các dòng dài chính là đặc trưng của Python One-liner.

5. Kiểm tra một list là tập con của list khác

Cho hai list a, b. kiểm tra xem a có chứa b hay không. Danh sách a chứa danh sách b nếu tất cả các phần tử của b đều có trong a. Cách giải sau đã có lần tôi trình bày, dùng thư viện operator và hàm built-in reduce, có thể dùng với mọi phiên bản Python 2.x:

>>> a = [1,2,3,4,5]
>>> b = [2,3,6]
>>> c = [2,3,4]
>>> reduce(operator.and_, map(a.__contains__, b))
False
>>> reduce(operator.and_, map(a.__contains__, c))
True

Từ Python 2.4 bạn có thể sử dụng set:

>>> set(a+b) == set(a)
False
>>> set(a+c) == set(a)
True
>>> set(c).issubset(a)
True
>>> set(b).issubset(a)
False
>>> set(c) <= set(a)
True
>>> set(b) <= set(a)
False

Từ Python 2.5 bạn có thể viết:

>>> all([x in a for x in b])
False
>>> all([x in a for x in c])
True

Module operator cung cấp cách dùng các toán tử như các hàm. Trong ví dụ 1 thực tế chúng ta dùng toán tử in thông thường. Các toán tử dùng như các hàm cho phép kết hợp với các hàm built-in khác để viết các lệnh Python rất ngắn gọn và thuận tiện. Một ví dụ (được lấy trong tài liệu Python) tính tích vô hướng hai vector:

sum(map(operator.mul, vector1, vector2))

Thật khó để viết ngắn hơn và chạy nhanh hơn như vậy. Các ví dụ trên càng nói rõ hơn điều tôi đã nhấn mạnh ở mục 3: các phiên bản Python càng về sau càng hỗ trợ tốt hơn việc viết các mã ngắn gọn và hiệu quả. Tuy vậy bạn phải cân nhắc lựa chọn giải pháp đúng cho phiên bản Python mà nó sẽ chạy.

6. Sắp xếp nhiều column

Cho các column a,b,c…có cùng kích thước. Hãy sắp xếp chúng theo thứ tự a,b,c.... Nội dung các dòng không thay đổi. Dưới đây là một ví dụ triển khai với 2 cột a, b:

>>> a = [3,3,2,2,1,1]
>>> b = ["c", "b", "b", "a", "c", "a"]
>>> a, b = zip(*sorted(zip(a, b)))
>>> a
(1, 1, 2, 2, 3, 3)
>>> b
('a', 'c', 'a', 'b', 'b', 'c')

Thật tuyệt!!!. Chúng đơn giản đến mức khó có thể ngắn gọn hơn nữa. Công thức trên trọn vẹn trên một dòng có ít hơn 80 ký tự. Tất cả chỉ có 4 lệnh. Ít nhất nó cũng gây cho tôi nhiều sự phấn khích và ngạc nhiên. Và các bạn sẽ thấy trên nhiều forum Python, việc tìm kiếm các “One-Liner” thực sự là thú vị và là trò chơi hấp dẫn của các Python guru.

7. Tổng kết

Khi kích thước dữ liệu đầu vào lớn một số trong các hàm trả về list trên đây cần được thay thế bằng các hàm trạng thái. Chẳng hạn việc chia một list thành nhiều list bằng nhau nên viết thành hàm trạng thái, sẽ dùng ít bộ nhớ và nhanh hơn:

def SplitInto(a, n):
    start = 0
    end = len(a) % n and len(a)/n + 1 or len(a)/n
    
    while start < end:
        yield a[start * n: (start + 1) * n]
        start += 1

Chuẩn viết mã Python là không quá 80 ký tự trên một dòng. Python One-Liner viết hết các lệnh Python trên một dòng, làm cho các line dài hơn bình thường. Mã Python khó đọc và khó hiểu hơn do cách viết cô đọng, các biến được đặt tên ngắn. Với các bài toán không mang tính cơ bản, các bạn nên hạn chế viết theo cách này.

Các chương trình viết trên một dòng không có nghĩa là nhanh nhất. Thậm chí trong đa số các trường hợp để viết trên một dòng người ta phải chọn cách viết mất nhiều thời gian chạy hơn. Do vậy khi kích thước dữ liệu lớn, tốt hơn hết hãy lựa chọn cách viết tối ưu, và chấp nhận mã dài hơn.

Tôi hi vọng rằng các bạn sẽ thích thú với các ví dụ trên đây. Chắc chắn còn nhiều cách giải khác cho mỗi vấn đề mà tôi đã nêu ra. Nếu các bạn tìm thấy chúng xin hãy vui lòng comment để mọi người cùng biết. Điều sau cùng tôi muốn nhấn mạnh là tuy việc tìm kiếm các lời giải một dòng cho mỗi vấn đề chỉ đơn giản là thú vui, ít mang tính ứng dụng - nhưng chúng thực sự sẽ thúc đẩy việc học hỏi và tìm kiếm kinh nghiệm của chúng ta.

Một số bài tập Python có thể triển khai trên một dòng:

  • Tạo ma trận đơn vị kích thước bất kỳ
  • Triển khai sàng Sieve of Eratosthenes
  • Triển khai dãy số Fibonacci.
  • Tạo một list chứa tất cả các hoán vị của một list khác (các phần tử có thể bằng nhau).

Hoaiptm.

..and..or..

written by Phạm Thị Minh Hoài, on Jan 2, 2010 11:25:00 PM.

Trong bài viết trước về Phần tử không tôi có nói về việc cần phải cẩn thận khi dùng phép toán có tương tác giữa phần tử không và None. Trong bài này tôi trình bày một ví dụ nhỏ minh họa rõ hơn một vấn đề mà nhiều bạn mới học có thể gặp phải. Đó là phép toán rút gọn ..and..or.. khi có sự tham gia của None.

Cấu trúc if.. else và phép gán giá trị theo điều kiện trong python:

if condition:
        x = somevalue
else:
        x = othervalue

Có thể được viết trên một dòng:

x = condition and somevalue or othervalue

Ví dụ:

>>> x = 1+1*2 == 3 and "OK" or "DUREX"
>>> x
'OK'

Thực tế có nhiều bạn thích cách viết này. Vì nó gọn hơn và mang tính python hơn. Tuy nhiên hãy cẩn thận khi sử dụng cấu trúc này. Chẳng hạn trong cấu trúc:

x = condition and func1() or func2()

Hàm func1()func2() có thể có giá trị None, khi đó kết quả kỳ vọng có thể không như bạn mong muốn. Xét ví dụ:

def func1():
        return None

def func2():
        return "some value"

x = 1 + 1 == 2 and func1() or func2()
print x

Kết quả:

some value

Biểu thức logic là True song vì func1() == None nên x = True and None or func2() = “some value”

Vì vậy hãy cẩn thận khi dùng cấu trúc ..and..or.. trừ khi bạn biết rõ các giá trị tham gia biểu thức này luôn luôn khác None.

Từ phiên bản 2.5 trở đi Python hỗ trợ cấu trúc:

x = TrueValue if Condition else FalseValue

Ví dụ:

x = "OK" if 1+1 == 2 else "DUREX"

Hoaiptm.

Phần tử không trong python

written by Phạm Thị Minh Hoài, on Dec 25, 2009 1:30:00 PM.

Bài viết này nêu lên một số khía cạnh thú vị (nhưng cũng rắc rối) của kiểu dữ liệu None cùng các phép toán liên quan đến nó, qua đó giúp các bạn mới học hiểu sâu sắc hơn về các kiểu dữ liệu có trong Python. Bài viết này có sử dụng một số khái niệm có trong lý thuyết nhóm chỉ nhằm mục đích minh họa những ý đồ của người viết.

1. Khái niệm phần tử không

Trong lý thuyết nhóm có khái niệm về phần tử không hay phần tử trung hòa. Phần tử không θ của một tập S trên phép toán * là phần tử thỏa mãn: a*θ = θ*a = a với mọi a trên S.

Các kiểu dữ liệu cơ bản trong Python cũng có phần tử không như vậy. Xem bảng tổng kết sau:

Kiểu dữ liệuPhép toánPhần tử khôngVí dụ
Số nguyên+00 + 69 = 69 + 0
Số thực+0.00.0 + 96.0 = 96.0 + 0.0
Danh sách+, extend[][1] + [] = [] + [1] = [1]
tuple+()(1,) + () = () + (1,) = (1,)
Tập hợpunionset([])set([1]).union(set([])) = set([]).union(set([1])) = set([1])
Chuỗi+“”“abc” + “” = “” + “abc” = “abc”
Từ điểnupdate{}{1:1}.update({}) == {}.update({1:1}) = {1:1}
Số phức+0+ 0j
LogicorFalseFalse or True = True or False = True

2. None và các toán tử logic

None là một tập hợp đặc biệt, chỉ có chính nó, mà cũng không phải là chính nó. Không phải là chính nó vì None bao hàm ý nghĩa là thiếu giá trị (denoting lack of value):

>>> type(None)
<type 'NoneType'>

None tương tác với tất cả các phần tử không:

>>> assert(([] and None) == [])
>>> assert(({} and None) == {})
>>> assert((0.0 and None) == 0.0)
>>> assert(("" and None) == "")
>>> assert((set([]) and None) == set([]))
>>> assert((() and None) == ())
>>> assert((0j and None) == 0J)
>>> assert((False and None) == False)

Nếu ta gọi S là tập hợp các phần tử không, bao gồm chính None, thì với phép toán and, None chính là phần tử không bên phải của S. Ai bảo None không phải là giá trị.

Tuy nhiên:

>>> assert((None and []) == None)
>>> assert((None and {}) == None)
>>> assert((None and set([])) == None)
>>> assert((None and "") == None)
>>> assert((None and 0) == None) 

Tương tự:

>>> assert((None or set([])) == set([]))
>>> assert((None or []) == [])
>>> assert((None or {}) == {})
>>> assert((None or "") == "")
>>> assert((None or 0) == 0)
>>> assert((None or 0j) == 0j)
>>> assert((None or ()) == ())

Nghĩa là None là phần tử không bên phải đối với tập S nói trên trong phép toán or.

Và:

>>> assert(({} or None) is None)
>>> assert(([] or None) is None)
>>> assert((0 or None) is None)
>>> assert((set([]) or None) is None)
>>> assert(("" or None) is None)
>>> assert((0j or None) is None)
>>> assert((() or None) is None)
>>> assert((0.0 or None) is None)

Như vậy khi None tương tác với các phần tử không, thứ tự các toán hạng là điều bạn cần chú ý.

Phép toán or giữa None và object bất kỳ không phải là phần tử không là ánh xạ đồng nhất bất kể thứ tự phép toán:

>>> set(['a']) or None
set(['a'])
>>> None or set(['a'])
set(['a'])
>>> None or "abc"
'abc'
>>> "abc" or None
'abc'
>>> None or {1:1}
{1: 1}
>>> {1:1} or None
{1: 1}

Phép toán and thì luôn cho kết quả None với bất kỳ phần tử nào không phải là phần tử không, không kể thứ tự toán hạng:

>>> assert((None and 1) is None)
>>> assert((1 and None) is None)
>>> assert(([1] and None) is None)
>>> assert((None and [1]) is None)
>>> assert(("abc" and None) is None)
>>> assert((None and "abc") is None)

Một biểu thức Logic chứa None có thể trả về None, nghĩa là không có giá trị. Điều này làm cho None trong python trở lên phức tạp và không giống với null trong C# hay nothing trong VB.NET. Trong VB.NET một biểu thức logic luôn luôn trả về giá trị logic.

None là tận cùng, là nhỏ hơn tất cả.

>>> None < 0.0 == 0 < {} < [1] < "" < ()
True

None không có bất kỳ một method nào, thậm chí chính nó là một method khi được dùng với filter hoặc map (xem phần dưới).

Cuối cùng NoneNone - đừng băn khoăn (^-^):

>>> None is None
True
>>> None == None
True

Việc hiểu rõ bản chất của None cùng các tương tác của nó với các phần tử không qua các phép toán logic là RẤT quan trọng khi bạn viết các lệnh if, filter…

Một hàm bất kỳ có thể trả về None nếu bạn viết return None, hoặc không return ở bất kỳ chỗ nào trong hàm. Một hàm như vậy khi tham gia vào biểu thực logic sẽ tạo ra những hiệu ứng mà bạn cần phải nắm rõ bản chất.

3. Loại bỏ các phần tử không trong danh sách

Nói chung các phần tử không sẽ không có ý nghĩa khi nó nằm trong danh sách. Một trong những cách để loại bỏ phần tử không là dùng filter. filter cùng với hàm func sẽ loại bỏ tất cả các phần tử trong danh sách mà tác động của hàm func lên phần tử này tạo ra phần tử không. Diễn giải dễ hiểu của nó như sau:

filter(func, list) 

<==>

S = [0, 0.0, [], (), {}, set([]), "", 0j, False]
def filter(func, list):
    return [x for x in list if func(x) not in S]

Ví dụ:

>>> filter(lambda x: not x, [3, 4, False, True, {1: 0}, []])
[False, []]

Để loại bỏ các phần tử không trong danh sách L, đơn giản là bạn dùng hàm ánh xạ đồng nhất f(x) = x: filter(lambda x: x, L). Hàm này tương đương với:

def filter(func, list):
    return [x for x in list if x not in S]

Cuối cùng một cách viết gây khó hiểu là thay thế lambda x:x bằng hàm None.

filter(None, list) <==> filter(lambda x: x, list)

Ví dụ:

>>> filter(None, [0, 0.0, "", 0+0j, set([]), (), [], {}, False])
[]
>>> filter(None, ["", "abc", " "])
['abc', ' ']
>>> filter(None, [1, 0, 2, 0.0])
[1, 2]

Ở đây chúng ta có cảm giác như None được dùng như một hàm. Thực ra không phải vậy, None có nghĩa là không có hàm nào ở đây cả, nói cách khác đối số đầu tiên của filter bị khuyết. Python lúc đó sẽ dùng hàm mặc định gì đó tương tự như lambda x: x.

4. Dùng None với map

>>> map(None, [1, 2, {1:2}])
[1, 2, {1: 2}]

map không thay đổi danh sách khi nó bị khuyết hàm tác động. Khi đó hàm None tương đương với ánh xạ đồng nhất (mặc dù không chính xác, vì thực ra là không có hàm nào cả, python có thể đã sử dụng hàm mặc định). Tuy nhiên dùng hàm None khi có hai danh sách trở lên thì lại tạo ra khả năng đặc biệt.

>>> map(None, [1, 2], [3, 4])
[(1, 3), (2, 4)]
>>> map(None, [1, 2], [3, 4], [5, 6])
[(1, 3, 5), (2, 4, 6)]

Khả năng này tương đương với zip

>>> zip([1, 2], [3, 4], [5, 6])
[(1, 3, 5), (2, 4, 6)]
>>> zip([1, 2], [3, 4])
[(1, 3), (2, 4)]

Diễn giải của nó như sau:

>>> map(lambda x, y: (x, y), [1, 2], [3, 4])
[(1, 3), (2, 4)]
>>> map(lambda x, y, z: (x, y, z), [1, 2], [3, 4], [5, 6])
[(1, 3, 5), (2, 4, 6)]

Một lần nữa trong mục này, mặc dù None bao hàm ý nghĩa về sự khuyết giá trị, song trong triển khai của hàm bất kỳ việc khuyết giá trị dẫn đến việc sử dụng các hàm mặc định. Lúc đó None có ý nghĩa là những gì mặc định. Đôi khi có thể ngắn gọn coi nó cũng là một hàm đặc biệt, hàm None.

Chú ý quan trọng: Các test của bài viết này được thử trên python 2.5.x

Hoaiptm.