Việc viết code Python hiệu quả không chỉ giúp cải thiện hiệu suất, mà còn làm cho code của bạn dễ đọc và bảo trì. Bài viết này, VietnamWorks inTECH sẽ chia sẻ với bạn 10 mẹo tối ưu hóa code Python hay nhất, giúp bạn viết những đoạn code nhanh chóng, dễ hiểu và hiệu quả hơn.
1. Sử dụng “Generators” để tiết kiệm bộ nhớ
Giả sử bạn cần phân tích một large_file
(tệp dữ liệu lớn) không thể tải toàn bộ vào RAM. Để xử lý vấn đề này hiệu quả, bạn có thể tạo một hàm generator process_large_file
để đọc tệp lớn theo từng dòng.
Generators không chỉ giúp xử lý dữ liệu lớn theo từng đợt mà còn rất tiết kiệm bộ nhớ, vì bạn không cần lưu trữ toàn bộ dữ liệu.
def process_large_file(file_path): """ with open(file_path, 'r') as file: for line in file: yield line # Specify the path to your large file log_file_path = 'path/to/your/large_file.txt' # Use the generator to process the large file line by line for line in process_large_file(log_file_path): print(line.strip()) # .strip() removes any extra whitespace or newline characters |
Đoạn mã trên hiển thị kết quả từng dòng, được lấy từ tệp large_file.txt
của bạn.
2. Sử dụng “.setdefault()
” trong Dictionaries
Giả sử bạn đang quản lý một hệ thống kho hàng và muốn theo dõi mức tồn kho của các sản phẩm khác nhau. Khi một sản phẩm mới được thêm vào hệ thống, bạn cần đảm bảo rằng nó có mức tồn kho mặc định nếu chưa được thiết lập trước đó.
Bằng cách thêm một key với giá trị mặc định đã chỉ định nếu key đó chưa có trong dictionary, bạn có thể sử dụng hàm setdefault()
để đơn giản hóa quá trình này
# Initial inventory inventory: dict[str, int] = {"jeans": 500, "top": 600} # Add more products with default stock levels if they are not already present products_to_add: list[str] = ["skirt", "shirt", "tee"] for product in products_to_add: inventory.setdefault(product, 500) # Print the final updated inventory print("Final updated inventory:", inventory) """ |
Cách này giúp bạn tránh phải kiểm tra và gán giá trị một cách rõ ràng, làm cho mã nguồn ngắn gọn và dễ đọc hơn.
3. Sử dụng Dictionaries để tránh "if-elif đến chết”
Giả sử bạn có nhiều hàm và muốn gọi các hàm đó tùy thuộc vào input của người dùng.
Cách phổ biến nhất để giải quyết vấn đề này là sử dụng các điều kiện if-elif, nhưng phương pháp này có thể trở nên rất dài và phức tạp nếu phải xử lý hàng trăm hàm.
Phương pháp thay thế là tạo một dictionary, trong đó key là giá trị bạn muốn kiểm tra và value là các hàm cần gọi.
from collections.abc import Callable # Function 1 def first(): print("Calling First Function...") # Function 2 def second(): print("Calling Second Function...") # Function 3 def third(): print("Calling Third Function...") # Function Default def default(): print("Calling Default Function...") # User Input options: int = int(input("Enter an option :", )) # Dictionary to hold options as key and functions as values funcs_dict : dict[int, Callable[[], None]] = {1: first, 2: second, 3: third} # Checking if the key exist and incase it doesn't then deafult function will run final_result = funcs_dict.get(options, default) final_result() |
Khi chạy chương trình, bạn có thể thấy những kết quả sau trên màn hình.
""" # Output: # When Option send was 0 Enter an option :0 Calling Default Function... # When Option send was 1 Enter an option :1 Calling First Function... # and so on... """ |
Lưu ý: Nếu người dùng yêu cầu bất kỳ thứ gì ngẫu nhiên, nó sẽ chạy hàm default().
4. Sử dụng “Counter” từ Collections Module
Khi làm việc với dữ liệu văn bản lớn, nhiệm vụ phổ biến nhất trong phân tích văn bản là xác định các từ khóa, và để làm điều này, bạn sẽ cần xác định tần suất xuất hiện của từng từ trong tài liệu cụ thể hoặc toàn bộ bộ sưu tập, tùy thuộc vào yêu cầu bài toán.
Counter cung cấp một cách đơn giản và hiệu quả để đếm các phần tử trong một iterable, giúp bạn tránh phải viết mã đếm phức tạp.
from collections import Counter import re # Read the text file with open("sample_text.txt", "r") as file: text = file.read() # Clean and Tokenize the text cleaned_text: str = re.sub(r'[^\w\s]', '', text.lower().split()) # Use Counter() to count the words word_counts: Counter = Counter(cleaned_text) # Printing second highest most common word most_commmon = counter.most_common(2) # passed in Number will denotes how many common numbers we want (counting starts from 1-n) print("Second Most Common Word is: ", most_commmon[0]) # print in zeroth index element from 2 most common ones """ |
Lưu ý: Ngoài ra, bạn cũng có thể thực hiện các phép toán số học, dễ dàng chuyển đối tượng Counter sang các cấu trúc dữ liệu khác như dictionary, và sử dụng các phương thức hữu ích như element()
, most_common()
, v.v.
5. Sử dụng “Memoization” để tối ưu code
Memoization là một kỹ thuật giúp tối ưu hóa các thuật toán đệ quy bằng cách lưu lại kết quả của các phép tính đã thực hiện. Khi gặp lại cùng một đầu vào, thay vì tính toán lại từ đầu, bạn chỉ cần sử dụng kết quả đã có sẵn.
Ví dụ điển hình của kỹ thuật này là bài toán Dãy Số Fibonacci, trong đó mỗi số là tổng của hai số trước đó.
import time def memo_fibonacci(num: int, dictionary: dict[int, int]): if num in dictionary: return dictionary[num] else: dictionary[num] = memo_fibonacci(num-1, dictionary) + memo_fibonacci(num-2, dictionary) return dictionary[num] # Catching using a Dictionary dictionary: dict[int, int] = {0: 1, 1: 1} # Elapsed time start_time: float = time.time() # Calling the function result: int = memo_fibonacci(48, dictionary) end_time: float = time.time() # Calculating the elapsed time elapsed_time: float = end_time - start_time print(f"Result: {result}") # Result: 7778742049 print(f"Elapsed time: {elapsed_time:.6f} seconds") # Elapsed time: 0.000133 seconds |
Lưu ý: Chắc chắn, kỹ thuật này giúp tiết kiệm đáng kể về thời gian. Tuy nhiên, cần nhớ rằng nó có sự đánh đổi giữa không gian và thời gian, vì bạn phải duy trì bộ nhớ cache để lưu trữ kết quả, điều này cần được cân nhắc cẩn thận.
6. Sử dụng “@decorators” để tránh sự lặp lại
Giả sử bạn đang xây dựng một dự án Python và muốn tính thời gian chạy của một hàm. Chắc chắn, như ví dụ trên, bạn có thể sử dụng chức năng time cho hàm đó, nhưng nếu bạn có hàng chục hoặc có thể là hàng trăm hàm thì sao?
Viết ‘start-time’ và ‘end-time’ cho từng hàm sẽ mất rất nhiều thời gian, thay vào đó, chúng ta có thể tạo một hàm elapsed_time
để làm việc này. Vậy @decorators
là gì?
Decorators là một tính năng độc đáo trong Python, cho phép bạn “bọc” một hàm đã có sẵn để thay đổi hoặc cải thiện chức năng mà vẫn giữ nguyên logic chính của nó, trước hoặc sau khi hàm đó thực thi.
Khi Python thấy ký hiệu @, nó sẽ hiểu rằng hàm dưới nó cần được truyền vào một hàm gọi là elapsed_time
, sau đó hàm này sẽ chạy trong elapsed_time
với các dòng code bổ sung được bao quanh, để đo thời gian cho bất kỳ số lượng hàm nào.
import time def elapsed_time(func): def wrapper(): start_time: float = time.time() func() end_time: float = time.time() - start_time print(f"{func.__name__}() took {end_time:.6f} seconds") return wrapper
def some_code(): # Simulating running code.. time.sleep(0.00002) # Calling the function some_code() # some_code() took 0.000009 seconds |
Chúng thường được sử dụng để ghi log, đo thời gian, kiểm soát quyền truy cập và nhiều tác vụ khác.
Lưu ý: Tuy nhiên, bạn không nên lạm dụng chúng, vì chúng có thể làm code của bạn trở nên khó hiểu và “che khuất” những gì code thực sự đang làm.
7. Sử dụng dataclass cho cấu trúc dữ liệu sạch
Việc viết lại phương thức __init__
trong các lớp thông thường chỉ để chứa các giá trị dữ liệu sẽ rất tốn thời gian và dễ gây ra lỗi.
Tuy nhiên, trong Python phiên bản 3.7, module dataclasses
là một cách hiệu quả hơn để lưu trữ dữ liệu sẽ được truyền giữa các phần khác nhau của chương trình.
from dataclasses import dataclass
class Employee: id_: int name: str salary: float e1 = Employee(id_=1, name='Tusk', salary=69999.99) print(e1) # Employees(id_=1, name='Tusk', salary=69999.99) |
Ở đây, kết quả đầu ra cũng tương đương với lớp Python chuẩn được triển khai sử dụng __repr__
.
Lưu ý: Chúng ta cũng có thể tùy chỉnh cách biểu diễn lớp Employee
của mình:
from dataclasses import dataclass
class Employee: id_: int name: str salary: float def __repr__(self): return f"Employee(id_={self.id_}, name={self.name}, salary={self.salary})" def __str__(self): return f"{self.name} earns ${self.salary}." e1 = Employee(id_=1, name='Tusk', salary=69999.99) print(repr(e1)) # Employee(id_=1, name=Tusk, salary=69999.99) print(str(e1)) # Tusk earns $69999.99. |
— Phương thức __repr__
cung cấp một cách biểu diễn rõ ràng và không mơ hồ về đối tượng Employee
.
— Phương thức __str__
cung cấp một mô tả dễ đọc và ngắn gọn hơn về đối tượng Employee
.
Hãy bắt đầu sử dụng dataclass để giảm thiểu mã lặp lại, giúp mã của bạn dễ đọc và dễ bảo trì hơn.
8. Sử dụng “match” để xử lý dữ liệu đầu vào một cách sạch sẽ
Từ Python 3.10, khớp mẫu cấu trúc (structural pattern matching) đã được thêm vào dưới dạng các mẫu match với các câu lệnh case đi kèm.
Giả sử chúng ta có một lớp "Point", đại diện cho một điểm trong hệ tọa độ 2D. Bây giờ, chúng ta sẽ tạo một hàm "where_is" để xử lý các trường hợp mà người dùng nhập vào để tìm điểm trong mặt phẳng 2D.
Câu lệnh match nhận một biểu thức và so sánh giá trị của nó với các mẫu case liên tiếp.
from dataclasses import dataclass # Defining a class using dataclass
class Point: x: int y: int # Match statements to handle different cases def where_is(point): match point: case Point(x=0, y=0): return ("Origin") case Point(x=0, y=y): return (f"Y={y}") case Point(x=x, y=0): return (f"X={x}") case Point(x, y): return("Somewhere else") # To catch anything else that the user inputs case _: return("Not a point") # Examples print(where_is(Point(0, 0))) # Output: Origin print(where_is(Point(0, 10))) # Output: Y=10 print(where_is(Point(10, 0))) # Output: X=10 print(where_is(Point(10, 10))) # Output: Somewhere else print(where_is("Not a point")) # Output: Not a point |
Sử dụng câu lệnh match-case, bạn có thể xử lý tất cả các trường hợp có thể xảy ra, đảm bảo việc khớp mẫu đầy đủ.
9(A). Sử dụng Toán Tử “all” thay vì “and”
Hãy tưởng tượng bạn đang xây dựng một hệ thống hồ sơ người dùng và muốn xác thực rằng tất cả các trường bắt buộc trong mẫu đều được người dùng điền đầy đủ.
Bạn có thể sử dụng hàm all, nó sẽ trả về True nếu và chỉ nếu tất cả các phần tử trong iterable đã cho đều là True, thay vì sử dụng các điều kiện and.
# User input from a registration form form_data: dict[str, str] = {"name" : "Nikita", "email": "analyticalnikita@gmail.com", "phone": "123478911"} # List of reuired fields required_fields: list[str] = ["name", "email", "phone"] # Using all operator if all(field in form_data for field in required_fields): print("All required fields are filled out.") else: print("Some required fields are missing or empty.") """ |
9(B). Sử dụng Toán Tử “any” thay vì “or”
Hàm any trả về True nếu bất kỳ phần tử nào trong iterable được cung cấp có giá trị True.
Ví dụ, bạn cần hạn chế một số quyền truy cập cho một số người dùng nhất định, dựa trên một số tiêu chí cụ thể. Trong trường hợp này, bạn có thể sử dụng any, thay vì dùng điều kiện or.
# List of permissions to the user user_permission: list[str] = ["read", "execute"] # Check if user has at least one of the required permissions required_permissions: list[str] = ["write", "read", "admin"] # Using "all" operator if any(permission in user_permission for permission in required_permissions): print(f"Since you have required permissions. Access is allowed.") else: print("You're a standard user. Not allowed the access.") """ |
Đây là một số ví dụ cho thấy cách sử dụng any và all để đơn giản hóa các điều kiện mà bình thường sẽ cần nhiều câu lệnh or hoặc and.
10. Sử Dụng Comprehensions để cú pháp ngắn gọn
Comprehension là một công cụ mạnh mẽ mà Python cung cấp cho bạn để làm việc với tất cả các kiểu dữ liệu iterable. Thay cho các vòng lặp nhiều dòng, nó sử dụng một dòng duy nhất, tùy thuộc vào tình huống.
Hãy cùng khám phá chúng từng bước một:
10(A). List Comprehensions
Ở đây, bài viết sẽ sử dụng ví dụ với câu lệnh if lồng nhau, để cho bạn thấy sức mạnh của list comprehension.
# Nested-if using List Comprehension fruits: list[str] = ["apple", "orange", "avacado", "kiwi", "banana"] basket: list[str] = ["apple", "avacado", "apricot", "kiwi"] [i for i in fruits if i in basket if i.startswith("a")] # ['apple', 'avacado'] |
Tương tự, bạn cũng có thể áp dụng vòng lặp for lồng nhau, nhưng đừng để nó làm cho comprehension của bạn trở nên khó đọc.
10(B). Tuple Comprehensions
Thực tế, tuple comprehensions không tồn tại trong Python. Thay vào đó, bạn có thể sử dụng generator expressions để tạo ra tuples.
# Generator expression converted to a tuple tuple(i**2 for i in range(10)) # (0, 1, 4, 9, 16, 25, 36, 49, 64, 81) |
10(C). Dictionary Comprehensions
Giả sử bạn có một danh sách apple_names
và muốn in ra một danh sách mới chứa độ dài của mỗi phần tử trong danh sách apple_names
.
Chắc chắn, bạn có thể sử dụng list comprehension ở đây. Nhưng bạn có biết rằng bạn thực sự có thể sử dụng cú pháp này để tạo ra một dictionary không? Đây chính là dictionary comprehension.
# Creating a list of apple names apple_names: list[str] = ["apple", "pineapple", "green apple"] # Creating a dictionary with apple names as keys and their lengths as values print({apple_name: len(apple_name) for apple_name in apple_names}) # {"apple": 5, "pineapple": 9, "green apple": 11} |
Có thể thấy, nó dễ đọc hơn so với việc sử dụng vòng lặp hoặc constructor của dict để tạo một dictionary.
10(D). Set Comprehensions
Bạn cũng có thể sử dụng việc lọc dựa trên các điều kiện nhất định trong comprehensions.
# Creating a set with condition print({i**2 for i in range(1, 11) if i > 5}) # {64, 36, 100, 49, 81} |
Lưu ý: Mặc dù comprehensions rất mạnh mẽ và dễ hiểu, nhưng điều này không có nghĩa là chúng phù hợp với tất cả các trường hợp, đặc biệt là khi logic quá phức tạp.
Lời kết
Tối ưu hóa mã nguồn là một phần quan trọng trong quá trình phát triển phần mềm, và Python mang đến cho lập trình viên rất nhiều công cụ mạnh mẽ để thực hiện điều đó. Hy vọng rằng những mẹo nhỏ trong bài viết sẽ giúp bạn nâng cao hiệu quả công việc, giảm thiểu lỗi và tối ưu hóa mã nguồn của mình.
TẠO TÀI KHOẢN MỚI: XEM FULL “1 TÁCH CODEFEE” - NHẬN SLOT TƯ VẤN CV TỪ CHUYÊN GIA - CƠ HỘI RINH VỀ VOUCHER 200K