2012-06-16 13 views
16

Hãy nói rằng tôi có một chức năng:đối số từ khóa Tháo bao bì, nhưng chỉ có những người phù hợp với chức năng

def foo(a = None, b=None, c=None): 
    return "a:%s, b:%s, c:%s" % (a,b,c) 

Tôi có một cuốn từ điển với một số (hoặc không có) của các đối số ở trên, mà còn với các phím được không được đặt tên đối số trong hàm, ví dụ:

d = {'a':1, 'x':4, 'b':2, 'y':5} 

Nếu tôi gọi sau, tôi sẽ gặp lỗi, vì 'x' và 'y' không phải là đối số từ khóa trong hàm foo.

foo(**d) # error 

Có cách thanh lịch để chuyển các đối số từ từ điển sang hàm, nhưng chỉ những giá trị có khóa khớp với đối số chức năng.

Vui lòng sửa tôi nếu thuật ngữ tham số/tham số của tôi bị tắt.

Trả lời

7

@Ashwini Chaudhary có cách giải quyết vấn đề rất sâu sắc. Tuy nhiên, nó yêu cầu thay đổi chữ ký của hàm foo của bạn.

Nếu bạn không muốn thay đổi chữ ký chức năng của bạn, bạn có thể sử dụng introspection để tìm ra những lý lẽ chức năng của bạn mong đợi:

arg_count = foo.func_code.co_argcount 
args = foo.func_code.co_varnames[:arg_count] 

args_dict = {} 
for k, v in d.iteritems(): 
    if k in args: 
     args_dict[k] = v 

foo(**args_dict) 
28
def foo(a = None, b=None, c=None,**extras): 
    return "a:%s, b:%s, c:%s" % (a, b, c) 

tại đây, **extras sẽ thu thập tất cả các đối số thêm/từ khóa bổ sung.

6

Thú vị câu hỏi. Tôi nghĩ rằng hầu hết mọi người trong cuộc sống thực đều sử dụng phương pháp @Ashwini Chaudhary.

Tôi đồng ý với @Rodrigue rằng có những lúc bạn không thể sửa đổi chữ ký cuộc gọi của hàm (mô-đun của người khác có thể).

Khi điều đó xảy ra, Sử dụng chức năng trang trí

from inspect import getargspec 
from funtools import wraps 

def allow_kwargs(foo): 
    argspec = getargspec(foo) 
    # if the original allows kwargs then do nothing 
    if argspec.keywords: 
     return foo 
    @wraps(foo) 
    def newfoo(*args, **kwargs): 
     #print "newfoo called with args=%r kwargs=%r"%(args,kwargs) 
     some_args = dict((k,kwargs[k]) for k in argspec.args if k in kwargs) 
     return foo(*args, **some_args) 
    return newfoo 


# with your function: 
@allow_kwargs 
def foo(a = None, b=None, c=None): 
    return "a:%s, b:%s, c:%s " % (a,b,c) 

# with someone_elses function: 
from some_place import foo 
foo = allow_kwargs(foo) 

@wraps từ functools giữ __name____doc__ chuỗi một cách tinh tế. Bạn cũng có thể:

  • xem FunctionMaker từ mô-đun trang trí nhưng đây phải là cách tiếp cận có thể tái sử dụng nhiều hơn.
  • sửa đổi newfoo để cho phép thêm các từ khóa không được chuyển qua.
Các vấn đề liên quan