Apelarea unei funcții cu o listă de argumente în python (Programare, Python, Funcție)

SurDin a intrebat.

Încerc să chem o funcție în interiorul altei funcții în python, dar nu găsesc sintaxa corectă. Ceea ce vreau să fac este ceva de genul următor:

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])

În acest caz, primul apel va funcționa, iar al doilea nu. ceea ce vreau să modific este funcția wrapper și nu funcțiile apelate.

6 răspunsuri
itsadok

Pentru a extinde puțin pe celelalte răspunsuri:

În linia:

def wrapper(func, *args):

* de lângă args înseamnă „ia restul parametrilor dați și pune-i într-o listă numită args„.

În linia:

    func(*args)

* de lângă args aici înseamnă „ia această listă numită args și „desface-o” în restul parametrilor.

Deci, puteți face următoarele:

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])

În wrapper2lista este trecută în mod explicit, dar în ambele wrappere args conține lista [1,2,3].

Comentarii

    26

  • Un lucru pe care nu l-am găsit menționat foarte des este cum să apelați o funcție cu *args, dacă aveți o listă sau un tupluplu pe care doriți să îl treceți. Pentru aceasta trebuie să o apelați astfel: wrapper1(func2, *mylist) –  > Por Ali.
  • *args în def wrapper(func, *args) este ceea ce method(params object[] args)este în C#. –  > Por Jim Aho.
  • Rețineți că *args trebuie să fie ultimul argument din definiția funcției. –  > Por Jim Aho.
  • The * next to args means "take the rest of the parameters given and put them in a list called args". Le pune într-un tuple, nu într-o listă. –  > Por Tomasz Nocoń.
Alex

Cel mai simplu mod de a înfășura o funcție

    func(*args, **kwargs)

… este de a scrie manual un wrapper care să apeleze func() în interiorul său:

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

În Python, funcția este un obiect, astfel încât puteți să-i treceți numele ca argument al unei alte funcții și să-l returnați. De asemenea, puteți scrie un generator de wrapper pentru orice funcție anyFunc():

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

Rețineți, de asemenea, că, în Python, atunci când nu știți sau nu doriți să numiți toate argumentele unei funcții, puteți face referire la o tupla de argumente, care este indicată prin numele acesteia, precedat de un asterisc în paranteze după numele funcției:

    *args

De exemplu, puteți defini o funcție care să primească un număr nelimitat de argumente:

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

Python oferă posibilitatea de a manipula și mai mult argumentele funcțiilor. Puteți permite ca o funcție să accepte argumente de tip cuvânt cheie. În cadrul corpului funcției, argumentele de tip cuvânt cheie sunt păstrate într-un dicționar. În parantezele de după numele funcției, acest dicționar este indicat prin două asteriscuri urmate de numele dicționarului:

    **kwargs

Un exemplu similar care tipărește dicționarul de cuvinte cheie argumente:

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

JimB

Puteți utiliza sintaxa *args și **kwargs pentru argumente de lungime variabilă.

Ce înseamnă *args și **kwargs?

Și din tutorialul oficial python

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

Comentarii

  • Deci, am nevoie ca acesta să obțină atât *args cât și **kwargs și să îl sun cu ele? –  > Por SurDin.
  • Nu, puteți folosi oricare dintre ele / sau, dar ele sunt adesea asociate împreună. În cazul dumneavoastră, aveți nevoie doar de *args. –  > Por JimB.
  • Ok, funcționează, dar tot nu mă lasă să trec o listă de argumente și trebuie să le trec separat. Nu mă deranjează prea mult, în situația mea actuală, dar tot ar fi bine să știu cum se poate face acest lucru. (Trebuie să fac wrapper(func2, x, y, z) și nu wrapper(func2, [x,y,z]) ) ) –  > Por SurDin.
  • Dacă doriți acest din urmă lucru, utilizați forma *args atunci când wrapper apelează func2, dar nu în „def wrapper”. –  > Por Alex Martelli.
Alan Rowarth

Răspunsul literal la întrebarea dvs. (pentru a face exact ceea ce ați cerut, schimbând doar wrapper-ul, nu și funcțiile sau apelurile de funcții) este pur și simplu să modificați linia

func(args)

pentru a se citi

func(*args)

Acest lucru îi spune lui Python să ia lista dată (în acest caz, args) și să transmită conținutul acesteia funcției ca argumente poziționale.

Acest truc funcționează pe ambele „părți” ale apelului de funcție, astfel încât o funcție definită astfel:

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

ar fi capabilă să accepte oricâte argumente poziționale îi aruncați și să le plaseze pe toate într-o listă numită args.

Sper că acest lucru vă ajută să clarificați puțin lucrurile. Rețineți că toate acestea sunt posibile și în cazul argumentelor de tip dicts/cuvinte cheie, utilizând ** în loc de *.

Joril

Trebuie să folosiți argumente de despachetare .

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)

P. Siehr

O mică completare la răspunsurile anterioare, deoarece nu am găsit o soluție pentru o problemă, care nu merită să deschid o nouă întrebare, dar care m-a condus aici.

Aici este un mic fragment de cod, care combină lists, zip() și *args, pentru a oferi un wrapper care poate face față unei cantități necunoscute de funcții cu o cantitate necunoscută de argumente.

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)

Rețineți că zip() nu oferă o verificare de siguranță pentru listele de lungime inegală, consultați zip iterators asserting for equal length in python.