2014-10-22 16 views
16

Giả sử tôi có một số funciton, fLàm cách nào để bỏ qua các đối số từ khóa không mong muốn được chuyển đến một hàm?

def f (a=None): 
    print a 

Bây giờ, nếu tôi có một cuốn từ điển như dct = {"a":"Foo"}, tôi có thể gọi f(**dct) và nhận được kết quả Foo in.

Tuy nhiên, giả sử tôi có từ điển dct2 = {"a":"Foo", "b":"Bar"}. Nếu tôi gọi f(**dct2) Tôi nhận được

TypeError: f() got an unexpected keyword argument 'b' 

Đủ công bằng. Tuy nhiên, có anyway để, trong định nghĩa của f hoặc trong kêu gọi của nó, nói với python để chỉ bỏ qua bất kỳ phím mà không phải là tên tham số? Ưu tiên phương thức cho phép xác định mặc định.

Trả lời

15

Là một phần mở rộng của câu trả lời đăng bởi @Bas, tôi sẽ đề nghị để thêm các đối số kwargs (đối số từ khóa chiều dài thay đổi) như tham số thứ hai đến chức năng

>>> def f (a=None, **kwargs): 
    print a 


>>> dct2 = {"a":"Foo", "b":"Bar"} 
>>> f(**dct2) 
Foo 

này hẳn sẽ đủ trường hợp của

  1. to just ignore any keys that are not parameter names
  2. However, it lacks the default values of parameters, which is a nice feature that it would be nice to keep
+0

Tôi nghĩ rằng đây là những gì OP đang tìm kiếm. –

+0

Cũng lưu ý rằng 'f (10, b = 20)' sẽ in '10' ở đây, điều này sẽ không đúng nếu bạn chỉ lấy' ** kwargs'. – abarnert

+0

Nhưng nếu chức năng được tạo bởi những người khác (ví dụ: thư viện nguồn mở), tôi không thể làm điều đó –

10

Điều này có thể được thực hiện bằng cách sử dụng **kwargs, cho phép bạn để thu thập tất cả các đối số từ khóa xác định trong một dict:

def f(**kwargs): 
    print kwargs['a'] 

nhanh kiểm tra:

In [2]: f(a=13, b=55) 
13 

EDIT Nếu bạn vẫn muốn sử dụng đối số mặc định, bạn giữ nguyên đối số ban đầu với giá trị mặc định, nhưng bạn chỉ cần thêm **kwargs để hấp thụ tất cả các đối số khác:

In [3]: def f(a='default_a', **kwargs): 
    ...:  print a 
    ...:  

In [4]: f(b=44, a=12) 
12 
In [5]: f(c=33) 
default_a 
+0

Chỉnh sửa hơi gây hiểu lầm. Điều quan trọng nhất bạn có thể làm với điều thứ hai mà bạn không thể làm với cái thứ nhất là lấy 'a' làm đối số vị trí. (Trừ khi bạn muốn lấy '* args' cũng như' ** kwargs' và tái tạo toàn bộ cơ chế ràng buộc đối số.) Chỉ cần xử lý một giá trị mặc định, mặt khác, là tầm thường — 'print kwargs.get (' a ',' default_a ') '. – abarnert

+0

Thật vậy, việc sử dụng 'kwargs.get()' sẽ là một cách khác để xác định một giá trị mặc định. Điều tốt đẹp về giải pháp của tôi là bạn có thể thấy rằng hàm có giá trị mặc định chỉ từ tiêu đề hàm, mà không cần phải thâm nhập vào phần thân của hàm. Rằng nó bây giờ cũng có lập luận vị trí là một số tác dụng phụ nhỏ. –

+0

Tôi nghĩ rằng API là một hiệu ứng lớn hơn nhiều so với khả năng nội tại của API đó. – abarnert

2

Nếu bạn không thể thay đổi định nghĩa hàm để lấy ** kwargs không xác định, bạn có thể lọc từ điển bạn chuyển vào bằng các đối số từ khóa bằng hàm argspec trong phiên bản cũ hơn của python hoặc phương pháp kiểm tra chữ ký trong Python 3.6.

import inspect 
def filter_dict(dict_to_filter, thing_with_kwargs): 
    sig = inspect.signature(thing_with_kwargs) 
    filter_keys = [param.name for param in sig.parameters.values() if param.kind == param.POSITIONAL_OR_KEYWORD] 
    filtered_dict = {filter_key:dict_to_filter[filter_key] for filter_key in filter_keys} 
    return filtered_dict 

def myfunc(x=0): 
    print(x) 
mydict = {'x':2, 'y':3} 
filtered_dict = filter_dict(mydict, myfunc) 
myfunc(**filtered_dict) # 2 
myfunc(x=3) # 3 
Các vấn đề liên quan