2010-01-18 32 views
13

Nếu tôi có một chức năng python như vậy:Nhận kwargs Bên Chức năng

def some_func(arg1, arg2, arg3=1, arg4=2): 

Có cách nào để xác định đối số được thông qua bởi từ khóa từ bên trong hàm?

EDIT

Đối với những người hỏi tại sao tôi cần điều này, tôi không có lý do thực sự, nó đã đưa ra trong một cuộc trò chuyện và tò mò có tốt hơn của tôi.

+1

Tôi không nghĩ vậy ... tại sao một người lại bận tâm với ** kw? – jldupont

+0

Tôi xin lỗi, nhưng nếu nó chỉ là sự tò mò của bạn, tôi sẽ bỏ phiếu để đóng, không có vấn đề thực sự, không có trường hợp sử dụng, và không ai sẽ gặp vấn đề bạn đang mơ. – SilentGhost

+0

Thực ra, tôi đã gặp phải vấn đề đó một lần. Tôi đã viết một hàm để tạo một trình bao bọc XML (thêm một thẻ bắt đầu và gắn thêm một thẻ kết thúc) xung quanh một số CDATA và muốn nó trông giống như 'def wrap (tag, contents = None, ** attrs):', nhưng sau đó chạy thẳng vào vấn đề mà các thuộc tính có thể có các ký tự mà các mã định danh Python không thể. Nhưng đó là một bài tập thú vị trong vài phút. –

Trả lời

14

Không, không có cách nào để làm điều đó trong mã Python với chữ ký này - nếu bạn cần thông tin này, bạn cần thay đổi chữ ký của hàm.

Nếu bạn nhìn vào API C C, bạn sẽ thấy rằng các đối số cách thực được chuyển đến hàm bình thường Python luôn là một bộ tuple cộng dict - tức là cách phản ánh trực tiếp chữ ký của *args, **kwargs. Sau đó, tuple và dict được phân tích thành các arg đặc biệt và được đặt tên trong chữ ký mặc dù chúng được truyền theo tên, và *a**kw, nếu có, chỉ lấy "tràn" từ phân tích cú pháp đó, nếu có - chỉ vào thời điểm này mã Python của bạn mới có được quyền kiểm soát, và sau đó thông tin bạn đang yêu cầu (cách là các đối số khác nhau được chuyển) không còn nữa.

Để nhận thông tin bạn yêu cầu, hãy thay đổi chữ ký thành *a, **kw và thực hiện phân tích/xác thực của riêng bạn - điều này sẽ "từ trứng đến trứng tráng", nghĩa là một số lượng công việc nhất định nhưng chắc chắn khả thi, trong khi những gì bạn đang tìm kiếm sẽ được "từ trứng tráng trở lại trứng" ... chỉ đơn giản là không khả thi ;-).

+0

+1: tương tự thú vị! – jldupont

+0

Không thực sự, nó làm tôi đói: ( – gorsky

1

bạn có muốn biết liệu arg31 vì nó được chuyển từ bên ngoài hoặc bởi vì nó là giá trị mặc định? Không có cách nào để làm điều này theo như tôi biết. Lý do chính, tôi nghi ngờ, rằng không cần phải có kiến ​​thức như vậy. Những gì thường được thực hiện như sau:

>>> def func(a, b=None): 
    if b is None: 
# here we know that function was called as: 
# func('spam') or func('spam', None) or func('spam', b=None) or func(a='spam', b=None) 

     b = 42 
1

Chỉ cần làm điều đó như thế này:

def some_func (arg1, arg2, arg3=None, arg4=None): 
    if arg3 is None: 
     arg3 = 1 # default value 
    if arg4 is None: 
     arg4 = 2 # default value 

    # do something 

Bằng cách đó bạn có thể thấy khi một cái gì đó đã được thiết lập, bạn cũng có thể làm việc với các cấu trúc mặc định phức tạp hơn (như danh sách) mà không cần chạy vào các vấn đề như sau đây:

>>> def test(arg=[]): 
     arg.append(1) 
     print(arg) 
>>> test() 
[1] 
>>> test() 
[1, 1] 
+0

Nhưng bạn vẫn không thể biết sự khác biệt giữa 'some_func (1, 2, None, 4)' và 'some_func (1, 2, arg4 = 4)', ví dụ. –

+1

Tại sao bạn cần điều đó? Các đối số được đặt tên là để bạn có thể để lại các tham số tùy chọn khác (vì vậy bạn không phải viết tất cả các tham số này) – poke

+0

Vâng, đó là câu hỏi, phải không? người có thể trả lời câu hỏi đó. –

2

bạn đang có khá nhiều sẽ phải xác định lại chức năng của bạn:

def some_func(*args, **kwargs): 

và tự mình sửa đổi. Không có cách nào để nói sự khác biệt giữa từng vị trí, thông qua từng từ khóa và mặc định.

9

Đây là giải pháp của tôi qua trang trí:

def showargs(function): 
    def inner(*args, **kwargs): 
     return function((args, kwargs), *args, **kwargs) 
    return inner 

@showargs 
def some_func(info, arg1, arg2, arg3=1, arg4=2): 
    print arg1,arg2,arg3,arg4 
    return info 

In [226]: some_func(1,2,3, arg4=4) 
1 2 3 4 
Out[226]: ((1, 2, 3), {'arg4': 4}) 

Có thể có một cách để làm sạch này lên xa hơn, nhưng điều này dường như ít xâm nhập đối với tôi và không yêu cầu phải thay đổi mã gọi.

Edit: Để thực sự kiểm tra nếu args đặc biệt được thông qua theo từ khóa, sau đó làm một cái gì đó như sau bên trong của some_func:

args, kwargs = info 
if 'arg4' in kwargs: 
    print "arg4 passed as keyword argument" 

Disclaimer: có lẽ bạn nên xem xét hay không, bạn thực sự quan tâm cách các đối số được thông qua. Toàn bộ cách tiếp cận này có thể là không cần thiết.

+0

cũng là người dân địa phương() tôi nghĩ –

Các vấn đề liên quan