Truyền từ điển cho hàm dưới dạng tham số từ khóa


345

Tôi muốn gọi một hàm trong python bằng từ điển.

Đây là một số mã:

d = dict(param='test')

def f(param):
    print(param)

f(d)

Bản in này {'param': 'test'}nhưng tôi muốn nó chỉ in test.

Tôi muốn nó hoạt động tương tự để có thêm thông số:

d = dict(p1=1, p2=2)
def f2(p1, p2):
    print(p1, p2)
f2(d)

Điều này có thể không?

Câu trả lời:


528

Tìm ra nó cho bản thân mình cuối cùng. Thật đơn giản, tôi chỉ thiếu toán tử ** để giải nén từ điển

Vì vậy, ví dụ của tôi trở thành:

d = dict(p1=1, p2=2)
def f2(p1,p2):
    print p1, p2
f2(**d)

57
nếu bạn muốn điều này giúp đỡ người khác, bạn nên viết lại câu hỏi của mình: vấn đề không phải là từ điển, điều bạn muốn là biến một câu lệnh thành tham số từ khóa
Javier

11
Điều đáng chú ý là bạn cũng có thể giải nén danh sách thành các đối số vị trí: f2 (* [1,2])
Matthew Trevor

10
"Dereference": thuật ngữ thông thường, trong ngữ cảnh Python này, là "giải nén". :)
mipadi

2
Điều này thật tuyệt, chỉ cần sử dụng nó với argparse / __ dict__ để làm cho việc thực hiện phân tích đối số dòng lệnh trực tiếp thành các tùy chọn cho một đối tượng lớp thực sự dễ dàng.
Horus

1
lý do chúng ta muốn giải nén một từ điển khi chuyển nó làm đối số cho một hàm là gì?
Mona Jalal

128
In[1]: def myfunc(a=1, b=2):
In[2]:    print(a, b)

In[3]: mydict = {'a': 100, 'b': 200}

In[4]: myfunc(**mydict)
100 200

Một vài chi tiết bổ sung có thể hữu ích để biết (những câu hỏi tôi đã có sau khi đọc nó và đã đi và kiểm tra):

  1. Hàm có thể có các tham số không có trong từ điển
  2. Bạn không thể ghi đè một tham số đã có trong từ điển
  3. Từ điển không thể có các tham số không có trong hàm.

Ví dụ:

Số 1: Hàm có thể có các tham số không có trong từ điển

In[5]: mydict = {'a': 100}
In[6]: myfunc(**mydict)
100 2

Số 2: Bạn không thể ghi đè một tham số đã có trong từ điển

In[7]: mydict = {'a': 100, 'b': 200}
In[8]: myfunc(a=3, **mydict)

TypeError: myfunc() got multiple values for keyword argument 'a'

Số 3: Từ điển không thể có các tham số không có trong hàm.

In[9]:  mydict = {'a': 100, 'b': 200, 'c': 300}
In[10]: myfunc(**mydict)

TypeError: myfunc() got an unexpected keyword argument 'c'

Theo yêu cầu trong các bình luận, một giải pháp cho Số 3 là lọc từ điển dựa trên các đối số từ khóa có sẵn trong hàm:

In[11]: import inspect
In[12]: mydict = {'a': 100, 'b': 200, 'c': 300}
In[13]: filtered_mydict = {k: v for k, v in mydict.items() if k in [p.name for p in inspect.signature(myfunc).parameters.values()]}
In[14]: myfunc(**filtered_mydict)
100 200

Một tùy chọn khác là chấp nhận (và bỏ qua) các kwarg bổ sung trong chức năng của bạn:

In[15]: def myfunc2(a=None, **kwargs):
In[16]:    print(a)

In[17]: mydict = {'a': 100, 'b': 200, 'c': 300}

In[18]: myfunc2(**mydict)
100

Lưu ý hơn là bạn có thể sử dụng các đối số và danh sách vị trí hoặc bộ dữ liệu theo cách hiệu quả giống như kwargs, đây là một ví dụ nâng cao hơn kết hợp cả đối số vị trí và từ khóa:

In[19]: def myfunc3(a, *posargs, b=2, **kwargs):
In[20]:    print(a, b)
In[21]:    print(posargs)
In[22]:    print(kwargs)

In[23]: mylist = [10, 20, 30]
In[24]: mydict = {'b': 200, 'c': 300}

In[25]: myfunc3(*mylist, **mydict)
10 200
(20, 30)
{'c': 300}

4
Sử dụng giải nén với print.format đặc biệt hữu ích. ví dụ:'hello {greeting} {name}'.format( **{'name': 'Andrew', 'greeting': 'Mr'})
Martlark

Câu hỏi cũ nhưng vẫn rất phù hợp. Cảm ơn đã phản ứng chi tiết. Bạn có biết cách nào để giải quyết trường hợp 3 không? Có nghĩa là ánh xạ python các mục của từ điển đến các tham số chức năng, khi có nhiều mục trong từ điển hơn có các tham số?
spencer

2
@spencer một giải pháp đã được thêm vào câu trả lời.
David park

33

Trong python, điều này được gọi là "giải nén" và bạn có thể tìm thấy một chút về nó trong hướng dẫn . Các tài liệu của nó hút, tôi đồng ý, đặc biệt là vì nó hữu ích như thế nào.


20
Tốt hơn là sao chép nội dung có liên quan của liên kết vào câu trả lời của bạn, thay vì dựa vào liên kết tồn tại cho đến hết thời gian.
Richard

3
@Richard đó là một quan điểm triết học sâu sắc về web, mà tôi không thể không đồng ý nhiều hơn! Than ôi, tôi thiếu không gian trong lề này để chia sẻ bằng chứng tuyệt vời của mình ...
llimllib

@llimllib, tôi sẽ phải hỏi Tiến sĩ Wiles rồi!
Richard

6

Ở đây ya đi - hoạt động như bất kỳ lặp đi lặp lại khác:

d = {'param' : 'test'}

def f(dictionary):
    for key in dictionary:
        print key

f(d)

Có vẻ như mọi người đang hạ thấp điều này vì nó đã trả lời câu hỏi ban đầu, không phải là câu hỏi được nhắc lại. Tôi đề nghị chỉ cần loại bỏ bài viết này bây giờ.
dotancohen

@dotancohen không, nó không bao giờ đúng, nó thất bại trong khối mã thứ hai luôn có câu hỏi. Nó đã quá đúng theo nghĩa đen, bản in là một ví dụ.
Dave Hillier

Nó trả lời câu hỏi mặc dù, nó chỉ không làm điều đó thông qua việc giải nén từ điển. Cách tiếp cận của ông là hoàn toàn hợp lệ dựa trên câu hỏi được đăng.
Natecat
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.