Gọi một hàm với danh sách đối số trong python


150

Tôi đang cố gắng gọi một hàm bên trong một hàm khác trong python, nhưng không thể tìm đúng cú pháp. Những gì tôi muốn làm là một cái gì đó như thế này:

def wrapper(func, args):
    func(args)

def func1(x):
    print(x)

def func2(x, y, z):
    return x+y+z

wrapper(func1, [x])
wrapper(func2, [x, y, z])

Trong trường hợp này, cuộc gọi đầu tiên sẽ hoạt động và cuộc gọi thứ hai sẽ không hoạt động. Những gì tôi muốn sửa đổi là chức năng bao bọc chứ không phải các chức năng được gọi.

Câu trả lời:


268

Để mở rộng một chút về các câu trả lời khác:

Trong dòng:

def wrapper(func, *args):

* Bên cạnh argscó nghĩa là "lấy phần còn lại của các tham số đã cho và đặt chúng vào danh sách có tên args".

Trong dòng:

    func(*args)

* Bên cạnh argsở đây có nghĩa là "đưa danh sách này được gọi là args và 'mở khóa' nó vào phần còn lại của các tham số.

Vì vậy, bạn có thể làm như sau:

def wrapper1(func, *args): # with star
    func(*args)

def wrapper2(func, args): # without star
    func(*args)

def func2(x, y, z):
    print x+y+z

wrapper1(func2, 1, 2, 3)
wrapper2(func2, [1, 2, 3])

Trong wrapper2, danh sách được thông qua rõ ràng, nhưng trong cả hai trình bao bọc argschứa danh sách [1,2,3].


26
Một điều mà tôi không thấy được đề cập rất thường xuyên là làm thế nào để gọi một hàm với * args, nếu bạn có một danh sách hoặc bộ dữ liệu mà bạn muốn vượt qua. Cho rằng bạn cần phải gọi nó như thế này: Wrapper1 (func2, * mylist)
Ali

* args in def wrapper(func, *args)là những gì method(params object[] args)trong C #.
Jim Aho

1
Lưu ý rằng *argsphải là đối số cuối cùng trong định nghĩa hàm.
Jim Aho

2
The * next to args means "take the rest of the parameters given and put them in a list called args".Nó đặt chúng trong một tuple, không phải là một danh sách.
Tomasz Nocoń 04/11/2016

20

Cách đơn giản nhất để bọc một chức năng

    func(*args, **kwargs)

... là tự viết một trình bao bọc sẽ gọi func () bên trong chính nó:

    def wrapper(*args, **kwargs):
        # do something before
        try:
            return func(*a, **kwargs)
        finally:
            # do something after

Trong hàm Python là một đối tượng, vì vậy bạn có thể chuyển tên của nó làm đối số của hàm khác và trả về nó. Bạn cũng có thể viết một trình tạo trình bao bọc cho bất kỳ hàm anyFunc () :

    def wrapperGenerator(anyFunc, *args, **kwargs):
        def wrapper(*args, **kwargs):
            try:
                # do something before
                return anyFunc(*args, **kwargs)
            finally:
                #do something after
        return wrapper

Cũng xin lưu ý rằng trong Python khi bạn không biết hoặc không muốn đặt tên cho tất cả các đối số của hàm, bạn có thể tham khảo một bộ các đối số, được biểu thị bằng tên của nó, trước dấu hoa thị trong dấu ngoặc đơn sau tên chức năng:

    *args

Ví dụ: bạn có thể định nghĩa một hàm sẽ lấy bất kỳ số lượng đối số nào:

    def testFunc(*args):
        print args    # prints the tuple of arguments

Python cung cấp cho thao tác hơn nữa trên các đối số chức năng. Bạn có thể cho phép một hàm lấy các đối số từ khóa. Trong thân hàm, các đối số từ khóa được giữ trong một từ điển. Trong ngoặc đơn sau tên hàm, từ điển này được biểu thị bằng hai dấu hoa thị theo sau là tên của từ điển:

    **kwargs

Một ví dụ tương tự in từ điển đối số từ khóa:

    def testFunc(**kwargs):
        print kwargs    # prints the dictionary of keyword arguments

11

Bạn có thể sử dụng cú pháp * args và ** kwargs cho các đối số độ dài thay đổi.

* Args và ** kwargs có nghĩa là gì?

Và từ hướng dẫn python chính thức

http://docs.python.org/dev/tutorial/controlflow.html#more-on-defining-fifts


Vì vậy, tôi cần nó để có được cả * args và ** kwargs và gọi nó với họ?
SurDin

1
Không, bạn có thể sử dụng / hoặc, nhưng chúng thường được ghép với nhau. Trong trường hợp của bạn, bạn chỉ cần * args.
JimB

Ok, nó hoạt động, nhưng nó vẫn không cho phép tôi vượt qua một danh sách các đối số và tôi phải vượt qua chúng một cách riêng biệt. Nó không làm phiền tôi nhiều, trong tình hình hiện tại của tôi, nhưng vẫn rất tốt để biết cách làm điều này. (Tôi cần thực hiện trình bao bọc (func2, x, y, z) chứ không phải trình bao bọc (func2, [x, y, z]))
SurDin

Nếu cái sau là những gì bạn muốn, hãy sử dụng biểu mẫu * args khi trình bao bọc gọi func2, nhưng không phải trong 'def Wrapper'.
Alex Martelli

10

Câu trả lời theo nghĩa đen cho câu hỏi của bạn (để thực hiện chính xác những gì bạn đã hỏi, chỉ thay đổi trình bao bọc, không phải các chức năng hoặc các chức năng gọi) chỉ đơn giản là để thay đổi dòng

func(args)

đọc

func(*args)

Điều này bảo Python lấy danh sách đã cho (trong trường hợp này args) và chuyển nội dung của nó cho hàm làm đối số vị trí.

Thủ thuật này hoạt động trên cả hai "mặt" của lệnh gọi hàm, do đó, một hàm được định nghĩa như sau:

def func2(*args):
    return sum(args)

sẽ có thể chấp nhận nhiều đối số vị trí như bạn ném vào nó và đặt tất cả chúng vào một danh sách được gọi args.

Tôi hy vọng điều này sẽ giúp làm rõ mọi thứ một chút. Lưu ý rằng điều này hoàn toàn có thể với các đối số từ khóa / từ khóa, sử dụng **thay vì *.


8

Bạn cần sử dụng các đối số giải nén ..

def wrapper(func, *args):
    func(*args)

def func1(x):
    print(x)

def func2(x, y, z):
    print x+y+z

wrapper(func1, 1)
wrapper(func2, 1, 2, 3)

0

Một bổ sung nhỏ cho các câu trả lời trước đây, vì tôi không thể tìm ra giải pháp cho một vấn đề, không đáng để mở một câu hỏi mới, nhưng đã dẫn tôi đến đây.

Dưới đây là một đoạn nhỏ mã, trong đó kết hợp lists, zip()*args, để cung cấp một wrapper có thể đối phó với một số tiền không rõ chức năng với một số tiền không rõ của đối số.

def f1(var1, var2, var3):
    print(var1+var2+var3)

def f2(var1, var2):
    print(var1*var2)

def f3():
    print('f3, empty')

def wrapper(a,b, func_list, arg_list):
    print(a)
    for f,var in zip(func_list,arg_list):
        f(*var)
    print(b)

f_list = [f1, f2, f3]
a_list = [[1,2,3], [4,5], []]

wrapper('begin', 'end', f_list, a_list)

Hãy nhớ rằng, điều zip()đó không cung cấp kiểm tra an toàn cho các danh sách có độ dài không bằng nhau, hãy xem các trình vòng lặp zip khẳng định độ dài bằng nhau của trăn .

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.