Wie kann man mehrere Argumente ausführen, um Funktionen zuzuordnen, bei denen eines in Python gleich bleibt?


155

Nehmen wir an, wir haben eine Funktion wie folgt hinzugefügt

def add(x, y):
    return x + y

Wir möchten die Map-Funktion für ein Array anwenden

map(add, [1, 2, 3], 2)

Die Semantik ist, dass ich jedem Element des Arrays 2 hinzufügen möchte. Die mapFunktion erfordert aber auch eine Liste im dritten Argument.

Hinweis: Der Einfachheit halber füge ich das Beispiel zum Hinzufügen hinzu. Meine ursprüngliche Funktion ist viel komplizierter. Die Option, den Standardwert für ydie Funktion zum Hinzufügen festzulegen, kommt natürlich nicht in Frage, da sie bei jedem Aufruf geändert wird.


20
Dies ist genau das gleiche wie in Lisp: map(add,[1,2,3],[2]*3) Im Allgemeinen mapwird eine Funktion als erstes Argument verwendet, und wenn diese Funktion ein K- Argument verwendet, müssen Sie K iterable verwenden:addTriple(a,b,c) -> map(addTriple,[...],[...],[...])
watashiSHUN

Antworten:


188

Eine Option ist ein Listenverständnis:

[add(x, 2) for x in [1, 2, 3]]

Mehr Optionen:

a = [1, 2, 3]

import functools
map(functools.partial(add, y=2), a)

import itertools
map(add, a, itertools.repeat(2, len(a)))

1
Ja, aber wie schnell ist es im Vergleich zur Kartenfunktion?
Shan

@ Shan: Sehr ähnlich, besonders wenn add()es sich um eine nicht triviale Funktion handelt
Sven Marnach

2
@ Shan: Schauen Sie sich in diesem Fall NumPy an. Wenn dies wirklich ein Problem für Sie ist, map()hilft der Geschwindigkeitsunterschied zwischen dem Listenverständnis nicht weiter.
Sven Marnach

3
@ Shan: Wie ich schon sagte, schauen Sie sich NumPy an. Dies kann helfen, Schleifen konderable zu beschleunigen, vorausgesetzt, sie können vektorisiert werden.
Sven Marnach

1
@abarnert: Es ist unklar, ob das OP Python 2 oder 3 verwendet. Um sicherzustellen, dass das Beispiel in Python 2 funktioniert, habe ich den Parameter eingefügt. (Beachten Sie, dass map()sich das Verhalten wie zip_longest()in Python 2 verhält, während es sich wie zip()in Python 3 verhält .)
Sven Marnach

60

In den Dokumenten wird ausdrücklich darauf hingewiesen, dass dies die Hauptverwendung ist für itertools.repeat:

Erstellen Sie einen Iterator, der das Objekt immer wieder zurückgibt. Wird unbegrenzt ausgeführt, sofern nicht das Argument times angegeben ist. Wird als Argument map()für invariante Parameter für die aufgerufene Funktion verwendet. Wird auch verwendet zip(), um einen invarianten Teil eines Tupeldatensatzes zu erstellen.

Und es gibt keinen Grund, len([1,2,3])als timesArgument zu gelten. mapstoppt, sobald das erste iterable verbraucht ist, so dass ein unendliches iterable vollkommen in Ordnung ist:

>>> from operator import add
>>> from itertools import repeat
>>> list(map(add, [1,2,3], repeat(4)))
[5, 6, 7]

Tatsächlich entspricht dies dem Beispiel repeatin den Dokumenten:

>>> list(map(pow, range(10), repeat(2)))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Dies ergibt eine nette Lazy-Functional-Language-y-Lösung, die auch in Python-Iterator-Begriffen perfekt lesbar ist.


2
+1 Dies sollte die akzeptierte Antwort sein. Es erstreckt sich natürlich auf eine beliebige Anzahl von Parametern, wobei einige Konstanten und andere Listen oder Generatoren vorhanden sind. ZB: def f(x,y,z): \\ return '.'.join([x,y,z])und dann: list(map(f, list('abc'), repeat('foo'), list('defgh')))kehrt zurück ['a.foo.d', 'b.foo.e', 'c.foo.f'].
Pierre D

5
In Python 2 muss das Längenargument angegeben werden repeat(), da es ausgeführt map()wird, bis der längste Iterator in dieser Version von Python erschöpft ist, und Nonealle fehlenden Werte ausfüllt . Zu sagen, dass "es keinen Grund gibt", den Parameter zu übergeben, ist falsch.
Sven Marnach

Der Kommentar von @SvenMarnach ist nicht unbedeutend: Das Verhalten von Python 3 und Python 2 variiert drastisch!
Agustín

36

Verwenden Sie ein Listenverständnis.

[x + 2 for x in [1, 2, 3]]

Wenn Sie wirklich , wirklich , wirklich verwenden möchten map, geben Sie ihm als erstes Argument eine anonyme Funktion:

map(lambda x: x + 2, [1,2,3])

16

Map kann mehrere Argumente enthalten, der Standardweg ist

map(add, a, b)

In Ihrer Frage sollte es sein

map(add, a, [2]*len(a))

Ich bin mir nicht sicher, was seine Frage bedeutete, aber ich denke, add akzeptiere 2 Werte und diese 2 sind nicht behoben und sollten vom Benutzer kommen, so wie arg1 kommt. Wie sollten wir in diesem Fall add (x, y) unter map aufrufen?
Bimlesh Sharma

15

Die richtige Antwort ist einfacher als Sie denken. Einfach machen:

map(add, [(x, 2) for x in [1,2,3]])

Und ändern Sie die Implementierung von add, um ein Tupel zu nehmen, dh

def add(t):
   x, y = t
   return x+y

Dies kann jeden komplizierten Anwendungsfall behandeln, bei dem beide Add-Parameter dynamisch sind.


14

Manchmal habe ich ähnliche Situationen (z. B. mit der Methode pandas.apply ) mithilfe von Verschlüssen gelöst

Um sie zu verwenden, definieren Sie eine Funktion, die dynamisch einen Wrapper für Ihre Funktion definiert und zurückgibt, wodurch einer der Parameter effektiv zu einer Konstanten wird.

Etwas wie das:

def add(x, y):
   return x + y

def add_constant(y):
    def f(x):
        return add(x, y)
    return f

Dann add_constant(y)gibt eine Funktion , die verwendet werden kann , hinzufügen yzu einem bestimmten Wert:

>>> add_constant(2)(3)
5

So können Sie es in jeder Situation verwenden, in der Parameter einzeln angegeben werden:

>>> map(add_constant(2), [1,2,3])
[3, 4, 5]

bearbeiten

Wenn Sie die Closure-Funktion nicht an einer anderen Stelle schreiben möchten, haben Sie immer die Möglichkeit, sie mithilfe einer Lambda-Funktion im laufenden Betrieb zu erstellen:

>>> map(lambda x: add(x, 2), [1, 2, 3])
[3, 4, 5]

13

Wenn Sie es zur Verfügung haben, würde ich die Verwendung von numpy in Betracht ziehen. Es ist sehr schnell für diese Art von Operationen:

>>> import numpy
>>> numpy.array([1,2,3]) + 2
array([3, 4, 5])

Dies setzt voraus, dass Ihre reale Anwendung mathematische Operationen ausführt (die vektorisiert werden können).


10

Wenn Sie wirklich wirklich die Map-Funktion verwenden müssen (wie meine Klassenzuweisung hier ...), können Sie eine Wrapper-Funktion mit 1 Argument verwenden und den Rest an die ursprüngliche Funktion in ihrem Hauptteil übergeben. dh:

extraArguments = value
def myFunc(arg):
    # call the target function
    return Func(arg, extraArguments)


map(myFunc, itterable)

Schmutzig und hässlich, macht immer noch den Trick


1
Ein Abschluss, ich denke, das fügt etwas hinzu, plus eins. Ähnlich einer Teilfunktion, wie es die akzeptierte Antwort hat.
Aaron Hall

1
myFuncmussreturn Func(arg, extraArguments)
PM 2Ring

Ich stehe korrigiert @ PM2Ring, das ist wahr; hat den Code aktualisiert.
Todor Minakov

Wo ist Func definiert? weil ich einen Namensfehler für Func
Nikhil Mishra

Funcist der Name Ihrer ursprünglichen Funktion - für OP eng wäre addzum Beispiel
Todor Minakov

6

Ich glaube, Starmap ist das, was Sie brauchen:

from itertools import starmap


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

list(starmap(test, [(1, 2, 3), (4, 5, 6)]))

Tippfehler in Ihrem Beispiel: Liste (Starmap (Test, [(1, 2, 3), (4, 5, 6)])
Teebu

Oh ja. Danke :)
Shqi.Yang

1

Übergeben mehrerer Argumente an eine mapFunktion.

def q(x,y):
    return x*y

print map (q,range(0,10),range(10,20))

Hier ist q eine Funktion mit mehreren Argumenten, die map () aufruft. Stellen Sie sicher, dass die Länge beider Bereiche dh

len (range(a,a')) and len (range(b,b')) are equal.

1

Im :nums = [1, 2, 3]

Im :map(add, nums, [2]*len(nums))

Aus:[3, 4, 5]


1
Dies gibt keine Antwort auf die Frage. Sie können nach ähnlichen Fragen suchen oder auf die verwandten und verknüpften Fragen auf der rechten Seite der Seite verweisen, um eine Antwort zu finden. Wenn Sie eine verwandte, aber andere Frage haben, stellen Sie eine neue Frage und fügen Sie einen Link zu dieser hinzu, um den Kontext bereitzustellen. Siehe: Fragen stellen, Antworten erhalten, keine Ablenkungen
Tim Diekmann

1

Sie können Lambda zusammen mit der Karte einschließen:

list(map(lambda a: a+2, [1, 2, 3]))

1
def func(a, b, c, d):
 return a + b * c % d
map(lambda x: func(*x), [[1,2,3,4], [5,6,7,8]])

Indem Sie den Funktionsaufruf mit einem Lambda umschließen und das Entpacken des Sterns verwenden, können Sie eine Zuordnung mit einer beliebigen Anzahl von Argumenten durchführen.


Lambda ist sehr langsam, verwenden Sie stattdessen Functools
Wang

0

Eine weitere Option ist:

results = []
for x in [1,2,3]:
    z = add(x,2)
    ...
    results += [f(z,x,y)]

Dieses Format ist sehr nützlich, wenn Sie mehrere Funktionen aufrufen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.