Kann eine variable Anzahl von Argumenten an eine Funktion übergeben werden?

345

Ähnlich wie bei der Verwendung von varargs in C oder C ++:

fn(a, b)
fn(a, b, c, d, ...)
David Sykes
quelle
5
Ich verweise die ehrenvolle Lottness auf Podcast 53: itc.conversationsnetwork.org/shows/…
David Sykes
2
Ich muss mit Mr. Lott in dieser Sache gehen. In den Python-Dokumenten erhalten Sie schnell eine maßgebliche Antwort auf diese Frage. Außerdem erhalten Sie ein Gefühl dafür, was sonst noch in den Dokumenten enthalten ist. Es ist zu Ihrem Vorteil, diese Dokumente kennenzulernen, wenn Sie in Python arbeiten möchten.
Brian Neal
@ DavidSykes Link ist kaputt
Dave Liu

Antworten:

446

Ja. Sie können *argsein Argument ohne Schlüsselwort verwenden . Sie können dann beliebig viele Argumente übergeben.

def manyArgs(*arg):
  print "I was called with", len(arg), "arguments:", arg

>>> manyArgs(1)
I was called with 1 arguments: (1,)
>>> manyArgs(1, 2, 3)
I was called with 3 arguments: (1, 2, 3)

Wie Sie sehen können, entpackt Python die Argumente als ein einziges Tupel mit allen Argumenten.

Für Schlüsselwortargumente müssen Sie diese als separates tatsächliches Argument akzeptieren, wie in der Antwort von Skurmedel gezeigt .

entspannen
quelle
8
Ebenfalls wichtig ... kann es vorkommen, dass eine unbekannte Anzahl von Argumenten an eine Funktion übergeben werden muss. In einem Fall wie diesem rufen Sie Ihre "manyArgs" auf, indem Sie eine Liste mit dem Namen "args" erstellen und diese an manyArgs wie diese "manyArgs (* args)" übergeben
wilbbe01
4
Das ist nah, aber das ist leider nicht allgemein genug: manyArgs(x = 3)scheitert mit TypeError. Skumedels Antwort zeigt die Lösung dafür. Der entscheidende Punkt ist, dass die allgemeine Signatur einer Funktion f(*list_args, **keyword_args)(nicht f(*list_args)) ist.
Eric O Lebigot
2
Die Art von argsist tuple. kwargsbedeutet Schlüsselwort args . Die Art von kwargsist dictionary.
RoboAlex
1
Nur for arg in args:zum Durchlaufen der übergebenen Argumente
MasterControlProgram
228

Hinzufügen zum Abwickeln des Beitrags:

Sie können auch mehrere Schlüsselwertargumente senden.

def myfunc(**kwargs):
    # kwargs is a dictionary.
    for k,v in kwargs.iteritems():
         print "%s = %s" % (k, v)

myfunc(abc=123, efh=456)
# abc = 123
# efh = 456

Und Sie können die beiden mischen:

def myfunc2(*args, **kwargs):
   for a in args:
       print a
   for k,v in kwargs.iteritems():
       print "%s = %s" % (k, v)

myfunc2(1, 2, 3, banan=123)
# 1
# 2
# 3
# banan = 123

Sie müssen in dieser Reihenfolge deklariert und aufgerufen werden, dh die Funktionssignatur muss * args, ** kwargs sein und in dieser Reihenfolge aufgerufen werden.

Skurmedel
quelle
2
Ich bin nicht sicher, wie Sie myfunc (abc = 123, def = 456) zum Laufen gebracht haben, aber in meiner (2.7) kann 'def' in dieser Funktion nicht übergeben werden, ohne einen SyntaxError zu erhalten. Ich nehme an, das liegt daran, dass def in Python eine Bedeutung hat. Versuchen Sie stattdessen myfunc (abc = 123, fgh = 567). (Ansonsten tolle Antwort und danke dafür!)
Dannid
@Dannid: Keine Ahnung, haha ​​... funktioniert auch nicht mit 2.6 oder 3.2. Ich werde es umbenennen.
Skurmedel
Wenn Sie "in dieser Reihenfolge angerufen" sagen, meinen Sie damit, dass Sie in dieser Reihenfolge bestanden haben? Oder etwas anderes?
Nikhil Prabhu
1
@ NikilPrabhu: Ja. Schlüsselwortargumente müssen beim Aufrufen an letzter Stelle stehen. Sie stehen immer an letzter Stelle, wenn der Aufruf auch Argumente enthält, die keine Schlüsselwörter sind.
Skurmedel
1
Für Python 3: Einfach print amit print(a)und kwargs.iteritems():mit austauschen kwargs.items().
MasterControlProgram
22

Wenn ich darf, ist Skurmedels Code für Python 2; Um es an Python 3 anzupassen, wechseln Sie iteritemszu itemsund fügen Sie Klammern hinzu print. Dies könnte verhindern, dass Anfänger wie ich auf Folgendes stoßen AttributeError: 'dict' object has no attribute 'iteritems'und anderswo suchen (z. B. Fehler "'dict' Objekt hat kein Attribut 'iteritems'", wenn versucht wird, write_shp () von NetworkX zu verwenden ), warum dies geschieht.

def myfunc(**kwargs):
for k,v in kwargs.items():
   print("%s = %s" % (k, v))

myfunc(abc=123, efh=456)
# abc = 123
# efh = 456

und:

def myfunc2(*args, **kwargs):
   for a in args:
       print(a)
   for k,v in kwargs.items():
       print("%s = %s" % (k, v))

myfunc2(1, 2, 3, banan=123)
# 1
# 2
# 3
# banan = 123
Calocedrus
quelle
12

Hinzufügen zu den anderen ausgezeichneten Beiträgen.

Manchmal möchten Sie die Anzahl der Argumente nicht angeben und Schlüssel für sie verwenden (der Compiler beschwert sich, wenn ein in einem Wörterbuch übergebenes Argument in der Methode nicht verwendet wird).

def manyArgs1(args):
  print args.a, args.b #note args.c is not used here

def manyArgs2(args):
  print args.c #note args.b and .c are not used here

class Args: pass

args = Args()
args.a = 1
args.b = 2
args.c = 3

manyArgs1(args) #outputs 1 2
manyArgs2(args) #outputs 3

Dann können Sie Dinge wie tun

myfuns = [manyArgs1, manyArgs2]
for fun in myfuns:
  fun(args)
Vladtn
quelle
2
def f(dic):
    if 'a' in dic:
        print dic['a'],
        pass
    else: print 'None',

    if 'b' in dic:
        print dic['b'],
        pass
    else: print 'None',

    if 'c' in dic:
        print dic['c'],
        pass
    else: print 'None',
    print
    pass
f({})
f({'a':20,
   'c':30})
f({'a':20,
   'c':30,
   'b':'red'})
____________

Der obige Code wird ausgegeben

None None None
20 None 30
20 red 30

Dies ist so gut wie das Übergeben variabler Argumente mittels eines Wörterbuchs

BN Venkataraman
quelle
3
Das ist schrecklicher Code. Weitaus besser wäre:f = lambda **dic: ' '.join(dic.get(key, 'None') for key in 'abc')
Metaperture
0

Ein anderer Weg, um dies zu erreichen, hängt neben den bereits erwähnten netten Antworten von der Tatsache ab, dass Sie optionale benannte Argumente nach Position übergeben können. Zum Beispiel,

def f(x,y=None):
    print(x)
    if y is not None:
        print(y)

Erträge

In [11]: f(1,2)
1
2

In [12]: f(1)
1
Transversalitätsbedingung
quelle