Python: wie funktioniert die functools cmp_to_key-Funktion funktioniert?
In Python, die beide list.sort
Methode und sorted
built-in-Funktion akzeptiert einen optionalen parameter namens key
, das ist eine Funktion, die, gegeben ein element aus der Liste gibt die Sortier-Schlüssel.
Älteren Python-Versionen verwendet einen anderen Ansatz mit Hilfe cmp
parameter statt, ist das eine Funktion, die, gegeben zwei Elemente aus der Liste gibt eine negative Zahl, wenn der erste kleiner als das zweite, null wenn es sind gleich, und eine positive Zahl, wenn die erste größer ist. An einem gewissen Punkt, dieser parameter wurde als veraltet markiert und war nicht enthalten in Python 3.
Den anderen Tag wollte ich zum Sortieren einer Liste von Elementen in einer Weise, dass ein cmp
Funktion war sehr viel leichter zu schreiben als ein key
ein. Ich wollte nicht zu verwenden, eine als veraltet markierte Funktion, so dass ich die Dokumentation gelesen und ich fand, dass es eine funtion namens cmp_to_key
im functools
Modul, das, wie sein name schon sagt, erhält ein cmp
Funktion und gibt einen key
einen... oder das, was ich dachte, bis ich Lesen Sie den source-code (oder zumindest eine gleichwertige version) dieses high-level Funktion im docs
def cmp_to_key(mycmp):
'Convert a cmp= function into a key= function'
class K(object):
def __init__(self, obj, *args):
self.obj = obj
def __lt__(self, other):
return mycmp(self.obj, other.obj) < 0
def __gt__(self, other):
return mycmp(self.obj, other.obj) > 0
def __eq__(self, other):
return mycmp(self.obj, other.obj) == 0
def __le__(self, other):
return mycmp(self.obj, other.obj) <= 0
def __ge__(self, other):
return mycmp(self.obj, other.obj) >= 0
def __ne__(self, other):
return mycmp(self.obj, other.obj) != 0
return K
Trotz der Tatsache, dass cmp_to_key
wie erwartet funktioniert, bekomme ich von der Tatsache überrascht, dass diese Funktion nicht wieder eine Funktion, aber eine K
Klasse statt. Warum? Wie funktioniert es? Meine Vermutung ist es, dass die sorted
Funktion, die intern prüft, ob die cmp ist eine Funktion oder eine Klasse K oder etwas ähnliches, aber ich bin mir nicht sicher.
P. S.: Trotz dieser Seltsamkeit, fand ich, dass die K-Klasse ist sehr nützlich. Überprüfen Sie diesen code:
from functools import cmp_to_key
def my_cmp(a, b):
# some sorting comparison which is hard to express using a key function
class MyClass(cmp_to_key(my_cmp)):
...
Diese Weise eine Liste von Instanzen von MyClass werden können, standardmäßig sortiert nach den definierten Kriterien in my_cmp
Du musst angemeldet sein, um einen Kommentar abzugeben.
Nein,
sorted
Funktion (oderlist.sort
) intern nicht brauchen, um zu überprüfen, ob das Objekt erhielt er eine Funktion oder eine Klasse . Alle, die es interessiert, ist, dass das Objekt erhielt er inkey
argument sollte Sie aufrufbar sein und sollte einen Wert zurückgeben, kann im Vergleich zu anderen Werten, wenn Sie aufgerufen.Klassen sind ebenfalls aufrufbar , wenn Sie anrufen, eine Klasse , erhalten Sie die Instanz der Klasse zurück.
Ihre Frage zu beantworten, müssen wir zunächst zu verstehen (mindestens auf einer grundlegenden Ebene), wie
key
argument funktioniert -Den
key
callable heißt für jedes element, und es erhält wieder das Objekt, mit dem es Sortieren soll.Nach Erhalt der neuen Sache, und es vergleicht diese auf andere Objekte (wieder erhielt durch den Aufruf der
key
aufrufbar mit dem anderen element).Nun ist die wichtige Sache hier zu beachten ist, dass die neue
object
erhalten, ist im Vergleich gegen andere gleiche Objekte.Nun auf Ihre entsprechende code, wenn Sie erstellen eine Instanz der Klasse, kann es im Vergleich zu anderen Instanzen der gleichen Klasse mit Ihr
mycmp
Funktion. Und Sortieren beim Sortieren der Werte vergleicht diese Objekte (in-Effekt) Anruf Ihresmycmp()
- Funktion, um zu bestimmen, ob der Wert kleiner oder größer als das andere Objekt.Beispiel mit print-Anweisungen -
Why 2 is being compared to 4 twice
, undwhy 5 is not compared to 2?
. Lassen Sie es mich wissen. Ich habe keine Ahnung, das ist zu überwältigend. Was passiert, wenncmp_to_key(-1)
zurückkey
Wert?Ich erkannte, dass, obwohl Sie nicht gerade eine Funktion, die K-Klasse ist ein callable, weil es ist eine Klasse! und Klassen sind callables, die, wenn Sie aufgerufen wird, erstellt Sie eine neue Instanz initialisiert durch den Aufruf der entsprechenden
__init__
und gibt dann diese Instanz.Diese Weise verhält Sie sich wie eine
key
- Funktion, da K erhält das Objekt, wenn Sie aufgerufen, und wickelt das Objekt in einen K-Instanz, die in der Lage zu sein, im Vergleich mit anderen K-Instanzen.Mich korrigieren, wenn ich falsch bin. Ich glaube, ich bin immer in die, ungewohnt für mich, meta-Klassen Territorium.
Ich schaue nicht in die Quelle, aber ich glaube, dass das Ergebnis der key-Funktion können Sie auch nichts, und daher auch ein vergleichbares Objekt. Und cmp_to_key nur Masken Erstellung von diejenigen K Objekte, die als im Vergleich zu jedem anderen beim Sortieren tut seine Arbeit.
Wenn ich versuche eine Art auf die Abteilungen und reverse-Zimmer zahlen wie diese:
Dass ist nicht das, was ich will, und ich denke, Sortieren ist nur dann stabil, auf jeden Anruf, der Dokumentation ist irreführend, imo:
Alten Stil Ansatz funktioniert, weil jedes Ergebnis aufrufen der K-Klasse gibt ein K Instanz und vergleicht die Ergebnisse der mycmp:
Es ist ein wichtiger Unterschied ist, dass man nicht mehrere Pässe einfach aus der box. Die Werte/Ergebnisse der key-Funktion haben werden, sortierbar relativ in Ordnung, nicht die Elemente sortiert werden. Daher ist die cmp_to_key Maske: erstellen Sie die vergleichbaren Objekte, die man braucht, um Sie zu bestellen.
Hoffe, das hilft. und vielen Dank für die Einsicht in die cmp_to_key code, hat mir sehr geholfen auch 🙂