Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Python

Mẹo tối ưu hóa code Python?


Mặc dù chúng ta đều biết Python không nhanh và hiệu quả bằng các ngôn ngữ biên dịch khác. Tuy nhiên, nhiều công ty lớn chứng minh rằng code Python có thể xử lý khối lượng công việc lớn, cho thấy nó không hề chậm như tưởng. Trong phần này, chúng ta sẽ xem xét một số mẹo để chương trình Python đúng đắn chạy nhanh hơn và hiệu quả hơn.

Mẹo 1: Ưu tiên dùng hàm tích hợp sẵn (built-in functions)

Mặc dù chúng ta có thể viết code hiệu quả trong Python, nhưng rất khó để vượt qua các hàm built-in (viết bằng C). Hình ảnh dưới đây liệt kê các hàm built-in của Python.

Mẹo tối ưu hóa code Python?

Mẹo 2: Dùng gán đa biến (multiple assignment) để hoán đổi biến

>>> # Thay vì dùng >>> x, y = y, x >>> # Hãy dùng cách này - nhanh hơn nhiều >>> temp = x >>> x = y >>> y = temp

Lưu ý: Ví dụ gốc trong bài viết có nhầm lẫn - cách gán `x, y = y, x` thực tế nhanh hơn và pythonic hơn cách dùng biến tạm. Cách viết pythonic khuyến khích là `x, y = y, x`.

Mẹo 3: Tránh biến toàn cục, dùng biến cục bộ nếu có thể

Python truy xuất biến cục bộ nhanh hơn biến toàn cục. Do đó, hãy tránh biến toàn cục nếu có thể.

Mẹo 4: Dùng "in" bất cứ nơi nào có thể

Để kiểm tra thành viên (membership) nói chung, hãy dùng từ khóa "in". Nó vừa gọn gàng vừa nhanh.

for key in sequence:    print ("Hello ", key)

Mẹo 5: Dùng "while 1" cho vòng lặp vô tận

Có lúc chúng ta phải chạy vòng lặp vô tận (ví dụ: socket lắng nghe). Dù "while True" thực hiện cùng thao tác, "while 1" là một phép nhảy đơn (single jump operation) nên nhanh hơn một chút.

>>> while 1:    # làm gì đó, nhanh hơn với while 1 >>> while True:    # làm gì đó, cùng thao tác nhưng chậm hơn cái trước

Mẹo 6: Dùng list comprehension

Từ Python 2.0, ta có thể dùng list comprehension để thay thế nhiều khối "for" và "while". List comprehension nhanh hơn vì nó được tối ưu hóa cho trình thông dịch Python để nhận diện mẫu dự đoán được trong vòng lặp. Nó dễ đọc hơn và trong hầu hết trường hợp tiết kiệm một biến đếm thêm.

Ví dụ tìm số chẵn từ 1 đến 25 trong một dòng:

>>> # Dùng list comprehension - cách tốt >>> print([i for i in range (25) if i%2 == 0]) [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24] >>> # Cách khác - không hiệu quả bằng i = 0 evens = [] while i< 25:    if i%2 == 0:       evens.append(i)    i += 1 print(evens) [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24]

Mẹo 7: Dùng generator để lấy giá trị theo nhu cầu (lazy evaluation)

Dùng generator Python tiết kiệm bộ nhớ và cải thiện hiệu năng. Ví dụ khi streaming video, bạn có thể gửi từng đoạn (chunk) byte thay vì toàn bộ luồng.

>>> chunkBytes = (1000 * i for i in range(1000)) >>> next(chunkBytes) 0 >>> next(chunkBytes) 1000 >>> next(chunkBytes) 2000 >>> next(chunkBytes) 3000 >>>

Mẹo 8: Dùng module itertools

Module itertools rất hữu ích và hiệu quả cho lặp và tổ hợp.

Tạo tất cả hoán vị cho list [1, 2, 3, 4, 5] trong vài dòng code Python:

>>> import itertools >>> iter1 = itertools.permutations([1, 2, 3,4]) >>> list(iter1) [(1, 2, 3, 4), (1, 2, 4, 3), (1, 3, 2, 4), (1, 3, 4, 2), (1, 4, 2, 3), (1, 4, 3, 2), (2, 1, 3, 4), (2, 1, 4, 3), (2, 3, 1, 4), (2, 3, 4, 1), (2, 4, 1, 3), (2, 4, 3, 1), (3, 1, 2, 4), (3, 1, 4, 2), (3, 2, 1, 4), (3, 2, 4, 1), (3, 4, 1, 2), (3, 4, 2, 1), (4, 1, 2, 3), (4, 1, 3, 2), (4, 2, 1, 3), (4, 2, 3, 1), (4, 3, 1, 2), (4, 3, 2, 1)]

Mẹo 9: Dùng module bisect để giữ list theo thứ tự đã sắp xếp

Đây là triển khai tìm kiếm nhị phân miễn phí và công cụ chèn nhanh cho chuỗi đã sắp xếp.

>>> import bisect >>> bisect.insort(list, element)

Chúng ta đã chèn phần tử vào list và bây giờ không cần gọi sort() nữa để giữ container được sắp xếp, điều này có thể rất tốn kém trên chuỗi dài.

Mẹo 10: Dùng dictionary và set để kiểm tra thành viên (membership)

Vì dictionary và set được triển khai bằng bảng băm (hash table), việc kiểm tra xem một phần tử có tồn tại trong dictionary hay set rất nhanh trong Python. Đôi khi tra cứu nhanh như O(1).

>>> lst = ['a', 'ab', 'abc'] # Chậm - kiểm tra thành viên với list >>> 'abc' in lst True >>> mySet = set(['a', 'ab', 'abc']) # Nhanh - kiểm tra thành viên với set hoặc dictionary >>> 'abc' in mySet True

Mẹo 11: Cache kết quả với Python decorator

Ký hiệu decorator Python là "@". Chúng ta có thể dùng decorator không chỉ cho tracing, locking hay logging, mà còn để trang trí hàm Python nhớ kết quả cần dùng sau (memoization).

>>> from functools import wraps >>> def memo(f):    cache = {}    @wraps(f)    def wrap(*arg):       if arg not in cache:          cache[arg] = f(*arg)       return cache[arg]    return wrap

Và ta có thể dùng decorator này trên hàm Fibonacci:

>>> @memo def fib(i):    if i<2:       return 1    return fib(i-1) + fib(i-2)

Ý tưởng cơ bản là nâng cấp (trang trí) hàm để nhớ mỗi số Fibonacci đã tính, nếu đã có trong cache thì không cần tính lại.