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

Đóng gói và Giải nén Tham số (Packing and Unpacking Arguments) trong Python


Nếu bạn đã làm một chút lập trình Python, bạn đã thấy từ "*args" và "**kwargs" trong các hàm Python. Nhưng chính xác chúng là gì?

Các toán tử * và ** thực hiện các phép toán khác nhau bổ sung cho nhau tùy thuộc vào nơi chúng ta sử dụng chúng.

Vì vậy khi chúng ta dùng chúng trong định nghĩa phương thức, như:

def __init__(self, *args, **kwargs):
    pass

Phép toán trên được gọi là 'packing' (đóng gói) vì nó gói tất cả các đối số vào một biến đơn lẻ mà lời gọi phương thức nhận được vào một tuple tên là args. Chúng ta có thể dùng tên khác ngoài args, nhưng args là cách phổ biến và pythonic nhất. Để hiểu tại sao gói vào một biến đơn lẻ, hãy xem ví dụ dưới đây:

Giả sử chúng ta có một hàm nhận ba đối số và chúng ta có một danh sách kích thước 3 chứa tất cả các đối số cho hàm. Bây giờ nếu chúng ta chỉ thử truyền danh sách cho hàm, lời gọi không hoạt động và ném lỗi.

Ví dụ 1

# Hàm nhận ba đối số
def func(a, b, c):
    print("{} {} {}".format(a, b, c))

# Danh sách các đối số
lst = ['python', 'java', 'csharp']

# Truyền danh sách
func(lst)

Kết quả

TypeError: func() missing 2 required positional arguments: 'b' and 'c'

Khi chúng ta đã 'packed' biến, thì bạn làm được những việc không thể với một tuple thông thường. args[0], args[1] và args[2] sẽ cho chúng ta đối số đầu tiên, thứ hai và thứ ba tương ứng. Nếu bạn chuyển tuple args thành list thì có thể thực hiện thao tác sửa đổi, xóa và thay đổi mục trong nó.

Để truyền các đối số đã đóng gói này cho phương thức khác, chúng ta cần làm unpacking (giải nén):

def __init__(self, *args, **kwargs):
    # some code here
    car(VehicleClass, self).__init__(self, *args, **kwargs)
    # some code below

Lại là toán tử *, nhưng lần này nó nằm trong ngữ cảnh lời gọi phương thức. Nó làm gì bây giờ là làm "nổ" mảng args và gọi phương thức như thể mỗi biến là độc lập. Dưới đây là ví dụ khác để hiểu rõ hơn:

Ví dụ 2

def func1(x, y, z):
    print(x)
    print(y)
    print(z)

def func2(*args):
    # Chuyển tuple args thành list để có thể sửa đổi
    args = list(args)
    args[0] = 'HTML'
    args[1] = 'CSS'
    args[2] = 'JavaScript'
    func1(*args)

func2('Python', 'Java', 'CSharp')

Kết quả

HTML
CSS
JavaScript

Từ kết quả trên, chúng ta có thể thay đổi cả ba đối số trước khi truyền chúng cho func1.

Tương tự chúng ta có thể giải quyết thông báo TypeError tìm thấy trong ví dụ 1.

Ví dụ: 1_1

# Hàm nhận ba đối số
def func(a, b, c):
    print("{} {} {}".format(a, b, c))

# Danh sách các đối số
lst = ['python', 'java', 'csharp']

# Truyền danh sách với unpacking
func(*lst)

Kết quả

python java csharp

Vì vậy trong trường hợp chúng ta không biết bao nhiêu đối số cần truyền cho hàm Python, chúng ta có thể dùng packing để gói tất cả đối số vào một tuple.

# Hàm dưới dùng packing để tổng số lượng đối số không xác định
def Sum(*args):
    sum = 0
    for i in range(0, len(args)):
        sum = sum + args[i]
    return sum

# Driver code
print("Function with 2 arguments & Sum is: \n", Sum(9, 12))
print("Function with 5 arguments & Sum is: \n", Sum(2, 3, 4, 5, 6))
print("Function with 6 arguments & Sum is: \n", Sum(20, 30, 40, 12, 40, 54))

Kết quả

Function with 2 arguments & Sum is: 21
Function with 5 arguments & Sum is: 20
Function with 6 arguments & Sum is: 196

Dưới đây là chương trình khác minh họa việc dùng cả packing và unpacking:

# Hàm với ba đối số
def func1(x, y, z):
    print("Argument One: ", x)
    print("\nArgument Two: ", y)
    print("\nArgument Three: ", z)

# Packing - Tất cả đối số truyền cho func2 được gói vào tuple *args
def func2(*args):
    # Để sửa đổi, chuyển args tuple thành list
    args = list(args)
    # Sửa đổi args[0] & args[1]
    args[0] = 'Hello'
    args[1] = 'TutorialsPoint'
    # Unpacking args và gọi func1()
    func1(*args)

# Driver code
func2("I", "Love", "Coding")

Kết quả

Argument One: Hello
Argument Two: TutorialsPoint
Argument Three: Coding

Sử dụng ** cho dictionary

# Chương trình minh họa unpacking các mục dictionary sử dụng **
def func(x, y, z):
    print("Dictionary first item: ", x)
    print("\nDictionary second item: ", y)
    print("\nDictionary third item: ", z)

d = {'x': 27, 'y': 54, 'z': 81}
func(**d)

Kết quả

Dictionary first item: 27
Dictionary second item: 54
Dictionary third item: 81

Ứng dụng

  • Dùng trong lập trình socket nơi cần gửi số lượng yêu cầu không xác định (vô hạn) đến server.
  • Dùng trong web framework như Django để truyền đối số biến đổi cho view functions.
  • Dùng trong wrapper functions yêu cầu truyền đối số biến đổi.