TÌM HIỂU VỀ *args VÀ **kwargs

Một trong những yêu cầu cơ bản của mọi ngôn ngữ lập trình là truyền các tham số cho hàm (function) trong các ngôn ngữ lập trình hướng thủ tục hoặc phương thức (method) trong các ngôn ngữ lập trình hướng đối tượng. Python cũng không ngoại lệ. 

Cách khai báo và truyền các tham số vào các phương thức (để bảo đảm tính nhất quán, chúng ta tạm sử dụng thuật ngữ phương thức cho cả phương thức và hàm trong Python) trong Python cũng tương tự như các ngôn ngữ lập trình phổ biến khác. Ví dụ như sau: 

Để khai báo một phương thức có sử dụng tham số: 

Hoặc để khai báo kiểu của tham số và kiểu của giá trị trả về từ phương thức, chúng ta có thể sử dụng cách khai báo mới hơn có dùng gợi ý kiểu (type hint). Kiểu khai báo này được đặc tả trong các PEP 483PEP 484 như trong ví dụ sau: 

Khi thực hiện chương trình, phương thức sẽ nhận các giá trị được truyền cho tham số như trong ví dụ sau: 

Chương trình này sẽ in ra dòng chữ “Hello, Hải” khi được thực hiện. 

Khi muốn truyền nhiều tham số cho phương thức và biết trước số lượng tham số, chúng ta có thể sử dụng cú pháp dưới đây để khai báo phương thức: 

Cách truyền tham số cho các phương thức với nhiều tham số như trên cũng tương tự như với phương thức chỉ có một tham số như trong ví dụ sau: 

Chương trình này sẽ in ra dòng chữ “Hello, Hải, Vân và An” khi được thực hiện. 

Đến đây, chúng ta đã biết cách để truyền một hoặc nhiều tham số cho phương thức và sử dụng chúng. Tuy nhiên, cách này chỉ áp dụng được nếu chúng ta biết được số lượng tham số cần truyền khi khai báo phương thức. Trong nhiều tình huống thực tế, chúng ta không biết trước được số lượng tham số cần truyền cho đến khi thực hiện chương trình. Ví dụ như trong phương thức greetings ở ví dụ trên, nếu lúc thực hiện chương trình chúng ta phát hiện ra rằng chúng ta có tên của hơn 3 người như giả định trong khai báo của phương thức, và cách duy nhất để khắc phục là phải sửa lại khai báo để phương thức có thể nhận vào nhiều tham số hơn 3, nhưng đây chỉ là giải pháp tạm thời vì nếu số tham số luôn thay đổi mỗi lần gọi phương thức thì chúng ta vẫn gặp rắc rối. Làm cách nào để giải quyết triệt để tình huống này? 

Câu trả lời là khai báo các tham số đặc biệt *args**kwargs trong Python. Đây là một trong những điểm mạnh của Python vì nó là một ngôn ngữ lập trình rất linh hoạt và luôn có một giải pháp dễ dàng cho nhiều trường hợp khác nhau. 

Chúng ta hãy bắt đầu với *args. Để khai báo một số không xác định các tham số cho một phương thức, chúng ta có thể sử dụng cú pháp như sau: 

Lưu ý là *args chỉ là quy ước (args là viết tắt của từ arguments cũng có nghĩa là tham số). Trong thực tế, ngoại trừ dấu * là bắt buộc, args có thể được thay đổi thành một từ bất kỳ. Ví dụ: cách khai báo như sau vẫn được xem là hợp lệ: 

Tuy nhiên, cách khai báo với *args là quy ước được sử dụng rộng rãi trong cộng đồng lập trình viên Python, vì vậy, chúng ta nên làm quen với cách khai báo này. 

Với cách khai báo này, *args sẽ hoạt động như là một danh sách (list) bên trong phương thức. Vì vậy, chúng ta có thể sử dụng các phương thức để truy cập danh sách với *args như trong ví dụ sau: 

Khi thực hiện, chương trình sẽ in ra kết quả như sau: 

Hải # print(args[0])

(‘Hải’, ‘Vân’) # print(args[:2])

Hải

Vân

An

Tâm # print(name) trong vòng lặp for

Rất hữu ích, phải không các bạn? Tuy nhiên, vẫn còn một hạn chế với *args là chúng ta phải truy cập các giá trị tham số qua vị trí (index) hoặc vòng lặp tuần tự vì bản chất của *args là một danh sách. Nếu chúng ta cần truy cập giá trị của tham số theo từ khóa (keyword) they vì vị trí, chúng ta sẽ cần đến **kwargs. 

Tương tự như với *args, chỉ có hai dấu * mở đầu trong cú pháp **kwargs là bắt buộc, còn lại là tùy chọn (kwargs là viết tắt của “key word arguments” – tham số theo từ khóa). Tuy nhiên, đây cũng là một quy ước quen thuộc trong cộng đồng Python và chúng ta nên làm quen với cách đặt tên này. 

Cách khai báo **kwargs cũng tương tự như *args và chúng cũng giống nhau là đều cho phép phương thức nhận một số lượng tham số bất kỳ. Tuy nhiên, khác với *args, các thành phần của **kwargs có thể được truy cập thông qua từ khóa thay vì chỉ mục. Chúng ta có thể thấy rõ hơn qua ví dụ sau: 

Khi thực hiện, chương trình sẽ in ra kết quả như sau: 

Hải # print(kwargs[“Name”]) 

20 # print(kwargs[“Age”]) 

Name = Hải   # for key, value in kwargs.items(): 

Age = 20 

Job = Engineer 

Ứng dụng: 

Một trong những ứng dụng thường gặp của *args và **kwargs là trong các phương thức wrapper (dùng để tạo ra các decorator cho các phương thức khác). Ví dụ như time wrapper dùng để đo thời gian thực hiện của các phương thức như trong ví dụ dưới đây: 

Định nghĩa phương thức wrapper: 

Sau đó, để đo thời gian thực hiện của một phương thức bất kỳ, chúng ta có thể gọi wrapper như sau: 

Đây là kết quả khi thực hiện chương trình: 

Bắt đầu thực hiện phương thức test…” 

Phương thức test hoàn tất!” 

Thời gian thực hiện: 5.006425619125366 seconds 

Rất hay, phải không các bạn? 

TLDR: Sử dụng *args và **kwargs cho các phương thức với số lượng tham số không xác định. *args thích hợp cho các trường hợp truy cập tuần tự hoặc theo chỉ mục (index), **kwargs thích hợp cho các trường hợp truy cập ngẫu nhiên đến các giá trị của tham số bằng từ khóa (keyword). 

Hy vọng bài viết này sẽ giúp cho các bạn hiểu rõ hơn về khái niệm *args và **kwargs cũng như ứng dụng trong thực tiễn 

Leave a Reply

Your email address will not be published. Required fields are marked *