2012-05-23 30 views
20

Tôi có hàm Python, fetch_data, truy cập API từ xa, lấy một số dữ liệu và trả về dữ liệu trong đối tượng phản hồi. Nó trông hơi giống như dưới đây:Nhận tất cả đối số và giá trị được chuyển đến hàm

def fetch_data(self, foo, bar, baz, **kwargs): 
    response = Response() 
    # Do various things, get some data 
    return response 

Bây giờ, nó có thể là dữ liệu đáp ứng nói: "Tôi có nhiều dữ liệu hơn, hãy gọi cho tôi với một tăng lên page tham số để có được nhiều hơn". Vì vậy, về cơ bản, tôi muốn lưu trữ "Phương thức gọi" (chức năng, tham số) trong đối tượng phản hồi, vì vậy tôi có thể có một số Response.get_more() xem xét chức năng và thông số được lưu trữ và gọi lại hàm đó (gần như) cùng thông số, trả lại một mới Response

Bây giờ nếu fetch_data được định nghĩa là fetch_data(*args, **kwargs) tôi chỉ có thể lưu trữ (fetch_data, args, kwargs) trong response. Tuy nhiên, tôi có self, foo, barbaz để lo lắng - Tôi chỉ có thể lưu trữ (fetch_data, foo, bar, baz, kwargs) nhưng đó là một số lượng rất không mong muốn lặp lại.

Về cơ bản, tôi đang cố gắng tìm ra cách, từ bên trong một hàm, nhận được một số hoàn toàn phổ biến *args**kwargs, bao gồm các tham số được đặt tên của hàm.

+0

Tại sao không chuyển foo, bar, baz và kwarg sang hàm dựng Response() để sau này gọi đến response.get_more() đã có các giá trị đó? – kurosch

+0

Vì điều đó không khắc phục được sự cố - tôi vẫn cần phải chạm vào 'Phản hồi' nếu tôi thay đổi chữ ký của' fetch_data'. –

+0

Có lẽ đó là một điều tốt? – kurosch

Trả lời

8

Tôi nghĩ một cách Pythonic hơn là biến chức năng của bạn thành một trình tạo, tìm nạp và nhập dữ liệu yield miễn là máy chủ tiếp tục trả về.

này nên kết quả trong mã gọn gàng và sẽ cho phép bạn sang bên kia bước tất cả sự phức tạp của việc bảo tồn những lập luận trên lặp đi lặp lại (Python kỳ diệu sẽ làm điều đó cho bạn :-))

+2

Đây chắc chắn là một trong những trường hợp phù hợp hơn với ứng dụng đó. Và cách đó cũng mang lại cơ hội OP để thêm phương thức 'get_more' trả về kết quả từ chuỗi lặp của máy phát tiếp theo. – Tadeck

+0

Vấn đề là có nhiều trường hợp bạn không quan tâm rằng có nhiều dữ liệu hơn, do đó việc trả lại một máy phát điện cảm thấy một chút không tự nhiên; có một 'next()'/'get_more()' trên đối tượng trả về cảm thấy thích hợp hơn rất nhiều ... –

+0

@KristianGlass: Tôi không chắc chắn tôi làm theo. Bạn có thể dễ dàng gọi (hoặc không gọi) 'next()' trên máy phát. http://stackoverflow.com/questions/4741243/how-to-pick-just-one-item-from-a-generator-in-python – NPE

0

kwargs sẽ không có ' foo ',' bar 'hoặc' bad 'làm khóa, vì vậy bạn có thể thêm các mục nhập đó (w/giá trị của chúng) vào kwarg và chỉ lưu trữ (fetch_data, kwargs).

+0

Đó là cùng một mức độ trùng lặp, nhưng theo một cách khác ... –

15

Không cái gì tôi muốn làm, nhưng bạn có thể sử dụng inspect.getargspec đến nội quan các đối số phương pháp của bạn mất:

>>> import inspect 
>>> def foobar(foo, bar, baz): 
...  return inspect.getargspec(foobar) 
... 
>>> foobar(1, 2, 3) 
ArgSpec(args=['foo', 'bar', 'baz'], varargs=None, keywords=None, defaults=None) 

này sau đó có thể được kết hợp với locals() để xây dựng lại lập luận của bạn:

>>> def foobar(foo, bar, baz): 
...  return [locals()[arg] for arg in inspect.getargspec(foobar).args] 
... 
>>> foobar(1, 2, 3) 
[1, 2, 3] 

Tuy nhiên, bạn thực sự chỉ cần ma thuật như vậy khi làm trang trí chức năng tiên tiến và tương tự. Tôi nghĩ nó quá mức ở đây.

31

Về cơ bản, tôi đang cố gắng tìm ra cách, từ bên trong một hàm, nhận được một số * args và ** kwargs được điền đầy đủ, bao gồm các tham số có tên của hàm.

Làm cách nào để lưu đối số qua số locals() khi bắt đầu chức năng?

def my_func(a, *args, **kwargs): 
    saved_args = locals() 
    print("saved_args is", saved_args) 
    local_var = 10 
    print("saved_args is", saved_args) 
    print("But locals() is now", locals()) 

my_func(20, 30, 40, 50, kwarg1='spam', kwarg2='eggs') 

Nó cung cấp cho sản lượng này:

saved_args is {'a': 20, 'args': (30, 40, 50), 'kwargs': {'kwarg1': u'spam', 'kwarg2': u'eggs'}} 
saved_args is {'a': 20, 'args': (30, 40, 50), 'kwargs': {'kwarg1': u'spam', 'kwarg2': u'eggs'}} 
But locals is now {'a': 20, 'saved_args': {...}, 'args': (30, 40, 50), 'local_var': 10, 'kwargs': {'kwarg1': u'spam', 'kwarg2': u'eggs'}} 

Hat tip: https://stackoverflow.com/a/3137022/2829764

2

inspect.getargspec bị phản đối kể từ phiên bản 3.0.Sử dụng signature() và đối tượng chữ ký, cung cấp API nội quan tốt hơn cho các cuộc gọi.

>>> from inspect import signature 
>>> def foo(a, *, b:int, **kwargs): 
...  pass 

>>> sig = signature(foo) 

>>> str(sig) 
'(a, *, b:int, **kwargs)' 

>>> str(sig.parameters['b']) 
'b:int' 

>>> sig.parameters['b'].annotation 
<class 'int'> 
Các vấn đề liên quan