chuyển đối số ** kwargs sang hàm khác với ** kwargs


152

Tôi không hiểu ví dụ sau, giả sử tôi có các chức năng này:

# python likes
def save(filename, data, **kwargs):
    fo = openX(filename, "w", **kwargs) # <- #1
    fo.write(data)
    fo.close()
# python doesnt like
def save2(filename, data, **kwargs):
    fo = openX(filename, "w", kwargs) # <- #2
    fo.write(data)
    fo.close()

def openX(filename, mode, **kwargs):
    #doing something fancy and returning a file object

Tại sao # 1 là giải pháp đúng và # 2 là sai? **kwargsvề cơ bản là một lệnh, vì vậy nếu tôi muốn truyền lại đối số cho openX tôi nghĩ rằng cách chính xác sẽ là không có **và chỉ đưa ra lệnh. Nhưng python rõ ràng không thích cái thứ hai và nói với tôi rằng tôi đã đưa ra 3 thay vì 2 đối số. Vì vậy, lý do đằng sau này là gì?

python 

5
Tôi tự hỏi tại sao bạn gọi nó **argstrong mã. Đây có thể là cái tên tồi tệ nhất có thể vì mọi người sẽ nhầm lẫn với nó*args
John La Rooy

1
Vâng, tôi không bao giờ thực sự sử dụng * args, vì vậy tôi sử dụng ** args ^^, nhưng tôi cũng có thể sửa đổi nó.

Câu trả lời:


155

Trong ví dụ thứ hai, bạn cung cấp 3 đối số: tên tệp, chế độ và từ điển ( kwargs). Nhưng Python mong đợi: 2 đối số chính thức cộng với đối số từ khóa.

Bằng cách thêm tiền tố vào từ điển bằng '**', bạn giải nén từ điển kwargscho các đối số từ khóa.

Một từ điển (loại dict) là một biến duy nhất chứa các cặp khóa-giá trị.

"Đối số từ khóa" là tham số phương thức khóa-giá trị.

Bất kỳ từ điển nào cũng có thể giải nén các đối số từ khóa bằng cách thêm tiền tố **vào trong khi gọi hàm.


5
giờ thì tôi đã hiểu. Tôi nghĩ rằng các từ khóa và dict là cùng một điều.

13
"Bất kỳ từ điển nào cũng có thể được mở rộng thành từ khóa bằng cách thêm tiền tố vào ** trong khi gọi hàm." <- thật tuyệt


8
Một ví dụ mã thực tế sẽ làm cho câu trả lời này rõ ràng hơn đáng kể.
OrangeDog

12

Các **cú pháp kể Python để đối số từ khóa thu thập vào một cuốn từ điển. Việc save2chuyển nó xuống dưới dạng đối số không phải từ khóa (đối tượng từ điển). Các openXkhông nhìn thấy bất kỳ đối số từ khóa nên **argskhông được sử dụng. Thay vào đó, nhận được một đối số không phải từ khóa thứ ba (từ điển). Để sửa lỗi thay đổi định nghĩa của openXhàm.

def openX(filename, mode, kwargs):
    pass

Cảm ơn bạn, nhưng tôi cũng muốn sử dụng openX mà không lưu, vì vậy tôi phải gắn bó với các từ khóa. Tôi nghĩ rằng việc chuyển từ khóa về cơ bản giống như truyền lại một từ điển, nhưng tôi không biết cho đến bây giờ :)

@xMRW Chúng không thể giống nhau vì bạn cũng có thể chuyển từ điển dưới dạng tham số cho bất kỳ chức năng nào. Số 1 của bạn là đúng sau đó.
Keith

8

Mở rộng câu trả lời của @gecco, sau đây là một ví dụ sẽ cho bạn thấy sự khác biệt:

def foo(**kwargs):
    for entry in kwargs.items():
        print("Key: {}, value: {}".format(entry[0], entry[1]))

# call using normal keys:
foo(a=1, b=2, c=3)
# call using an unpacked dictionary:
foo(**{"a": 1, "b":2, "c":3})

# call using a dictionary fails because the function will think you are
# giving it a positional argument
foo({"a": 1, "b": 2, "c": 3})
# this yields the same error as any other positional argument
foo(3)
foo("string")

Tại đây bạn có thể thấy cách giải nén từ điển hoạt động và tại sao gửi từ điển thực tế không thành công


1

Bởi vì một từ điển là một giá trị duy nhất. Bạn cần sử dụng mở rộng từ khóa nếu bạn muốn vượt qua nó như một nhóm các đối số từ khóa.


xin lỗi nhưng "mở rộng từ khóa" là gì? ý bạn là tôi nên sử dụng dict_var thay vì ** args và chỉ sử dụng def func (argument, dict_var = 0) ... func (1, {1: "a", 2: "b"})

1

Đối với # 2 args sẽ chỉ là một tham số chính thức có giá trị dict, nhưng không phải là tham số loại từ khóa.

Nếu bạn muốn chuyển tham số loại từ khóa vào đối số từ khóa Bạn cần cụ thể ** trước từ điển của mình, có nghĩa là ** đối số

kiểm tra điều này để biết thêm chi tiết về cách sử dụng ** kw

http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/


Vì vậy, có một sự khác biệt lớn giữa ** kwargs và dict?

cảm ơn bạn, tôi luôn muốn đọc thêm về các chủ đề tôi không hiểu.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.