@ Juliantaylor hat dies in einer Pandas-Ausgabe
Das Beispiel aus dem Ticket:
import numpy as np
import random
random.sample(np.array([1,2,3]),1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/user1/py33/lib/python3.3/random.py", line 298, in sample
raise TypeError("Population must be a sequence or set. For dicts, use list(d).")
TypeError: Population must be a sequence or set. For dicts, use list(d).
Dies tritt bei 3.3 mit 1.7.0rc1.dev-3a52aa0 und bei 3.2 mit 1.6.2 auf.
2.7 bleibt natürlich unberührt.
Der relavente Code aus cpython / Lib / random.py: 297
from collections.abc import Set as _Set, Sequence as _Sequence
def sample(self, population, k):
# ...
if not isinstance(population, _Sequence):
raise TypeError("Population must be a sequence or set. For dicts, use list(d).")
Ich konnte mit einem ähnlichen Test keinen anderen Ort in der stdlib finden, aber lib2to3
zeigte eine angenommene Äquivalenz:
lib2to3/fixes/fix_operator.py
5:operator.isSequenceType(obj) -> isinstance(obj, collections.Sequence)
in 2.7
In [6]: operator.isSequenceType(np.array([1]))
Out[6]: True
aber in 3.3 / 3.2
>>> isinstance(np.array([1]), collections.Sequence)
False
Python 3.x führt einfach eine strengere Überprüfung in random.sample
als Python 2.x. Unter 2.x ist numpy auch keine Sequenz-Unterklasse (ndarray hat keine Methoden index
, count
oder __reversed__
). Ich denke, Sie können dies entweder als Missbrauch von random.sample
oder als Abwärtskompatibilitätspause von Python 3.x betrachten.
Fair genug, aber das heißt, wir könnten leicht eine Sequenz erstellen,
da all diese Methoden sinnvoll und unkompliziert wären
implementieren. Tatsächlich würde es ausreichen, nur davon zu erben, da Sequence
bietet alle fehlenden Methoden als Mixins.
Am 2. Dezember 2012 um 13:30 Uhr schrieb "Ralf Gommers" [email protected] :
Python 3.x führt in random.sample einfach eine strengere Prüfung durch als
Python 2.x. Auf 2.x ist numpy auch keine Sequenzunterklasse (ndarray hat keine
Index-, Zähl- oder umgekehrte Methoden). Ich denke, Sie können dies als betrachten
Entweder Missbrauch von random.sample oder eine Abwärtskompatibilität
Python 3.x.- -
Antworten Sie direkt auf diese E-Mail oder sehen Sie sie sich auf Gi tHubhttps an: //github.com/numpy/numpy/issues/2776#issuecomment -10929601.
Ich hätte dasselbe gesagt, wenn nicht das 2to3-Beispiel gewesen wäre, das dies subtiler macht.
Index und Anzahl werden nicht benötigt Ich glaube: Link ,
Alle abstrakten Methoden für Sequence
sind bereits implementiert. Die anderen haben Standardimplementierungen.
Das Problem ist, dass MutableSequence
tatsächlich korrekter ist und insert
nicht implementiert ist.
Vergessen Sie 0-d-Arrays nicht, ich bin mir nicht sicher, was gerade mit ihnen passiert, aber sie sind nicht wirklich eine Sequenz, oder?
Hmm, Sequence
ist für unveränderliche Objekte gedacht, einige der Methoden von MutableSequence
(Erweitern, Pop) sind nicht sinnvoll. Also ja, wir könnten diese 3 Methoden hinzufügen, aber es fühlt sich nicht ganz richtig an.
Mir scheint, es gibt wirklich keinen Grund für random.sample
, eine Sequence
Instanz zu benötigen.
__setitem__
ist implementiert, aber nicht __delitem__
, also vielleicht SomewhatMutableSequence
?
Es ist sinnvoll, wenn Sie die Schnittstelle so interpretieren, dass "eine Sequenz all diese Elemente enthalten sollte, einige jedoch möglicherweise."
haben schreckliche O () ", weshalb sie naive Implementierungen einiger Methoden anbieten.
Sicherlich ist es nicht die Semantik von insert
, pop
, die im Kontext eines ndarray unklar ist.
Ich bin mir jedoch nicht sicher, was das Richtige in Bezug auf die Iteration über ein 0-d-Array ist.
Man könnte argumentieren, dass das Anbieten einer __iter__
-Methode eher eine TypeError
eine erhöht
StopIteration
ist sowieso eine Verletzung der Ententypisierung.
edit : Obwohl ich sicher bin, dass das keine nachlässige Entscheidung war.
ndarray könnte nur eine Sequenz sein, das heißt nicht, dass es unveränderlich sein muss.
Übrigens. Die Implementierung der CPython-Liste unterstützt auch kein effizientes Einfügen, Popup und Erweitern, ist jedoch weiterhin eine MutableSequence
ndarray kann In-Place-Insert / Pop / Extend nicht unterstützen (ndarrays haben eine feste Größe). Obwohl es sich um eine veränderbare Sequenz handelt, handelt es sich einfach nicht um Python MutableSequence
(und wird es auch nie sein). Es kann und sollte jedoch die Schnittstelle Sequence
unterstützen.
Es wäre schön, wenn random.sample
dies nicht überprüfen würde, aber bei näherer Betrachtung hat es einen plausiblen Grund - es gibt eine Reihe verschiedener Implementierungen für verschiedene Arten von Eingabeargumenten, daher braucht es eine Möglichkeit zwischen ihnen zu unterscheiden. Es kann nicht einfach mit der Indizierung beginnen und auf das Beste hoffen. Vielleicht könnten wir einen Fehler melden und versuchen, sie davon zu überzeugen, standardmäßig auf die Sequenzimplementierung für nicht erkannte Typen zurückzugreifen, aber das früheste, das helfen könnte, ist 3.4 ...
Der Punkt über 0-d-Arrays ist jedoch gut; 0-d-Arrays unterstützen die Schnittstelle Sequence
(sie sind nicht einmal Iterable
). Aber für Python-Zwecke ist es nicht allzu schrecklich, wenn sie lügen, Sequence
und dann auf den tatsächlichen Zugriff warten, um einen Fehler auszulösen - Enten-Eingabe bedeutet, dass Sie immer scheitern können, wenn Sie wollen :-). Es ist wahrscheinlich irgendwie möglich, dass isinstance(a, Sequence)
für mehrdimensionale Arrays erfolgreich ist und für 0-d-Arrays fehlschlägt. Wenn wir das schaffen können, dann cool. Aber selbst wenn wir nicht das Beste tun können, ist es wahrscheinlich immer noch, Ndarrays zu Sequence
.
Beachten Sie, dass MaskedArray bereits eine count
-Methode hat. Wenn Sie also eine in ndarray hinzufügen, die etwas anderes bewirkt, wird dies nicht mehr funktionieren.
0-D-Arrays werden mit ein paar praktischen Methoden besser als Skalare betrachtet (zumindest sehe ich sie so). Abgesehen davon, dass sie nicht iterierbar sind, sind sie auch nicht indizierbar, was noch seltsamer ist, wenn Sie sie als Arrays betrachten. Daher ist es imho kein großes Problem, 0-D-Arrays auf eine andere Weise inkonsistent zu machen.
@njsmith wo sehen Sie mehrere Implementierungen? Nach der Überprüfung der isinstance (Sequenz) sehe ich nur len(population)
und dann eine Konvertierung in eine Liste. http://hg.python.org/cpython/file/22d891a2d533/Lib/random.py
Die Typen Pandas Series und DataFrame verfügen außerdem über inkompatible Zählmethoden und ein Indexattribut.
@rgommers : Hmm, du hast recht, ich wurde durch die Fehlermeldung in die Irre geführt und dachte, dass sie auch ganze Zahlen als Abkürzung für range()
akzeptiert, was nicht der Fall ist. Trotzdem möchten sie ein unterschiedliches Verhalten für Mengen, Sequenzen und Zuordnungen definieren. Vielleicht können wir sie davon überzeugen, dass sie es wechseln sollten
if isinstance(population, _Set):
population = tuple(population)
if isinstance(population, _Mapping):
raise Blarrrgh()
# Otherwise assume that we have a sequence and hope
Das ist auch ein guter Punkt in Bezug auf die vorhandenen ndarray-Unterklassen. Es sieht nicht so aus, als gäbe es eine Möglichkeit zu sagen, dass ndarray ein Sequence
aber seine Unterklassen sind nicht :-(. Welche Option ist also am wenigsten schlecht, da einige dieser Unterklassen die Sequence
nicht erfüllen können
Sequence
-kompatible Versionen. Dies scheint für die count
-Methoden machbar zu sein, aber das Ändern des Namens von Series.index
wäre für die Pandas-Leute äußerst störend. (DataFrame ist keine Unterklasse von ndarray, daher ist es technisch nicht relevant, außer ich denke, die Serie und DataFrame sollten synchron gehalten werden.) Ich denke, wir können @wesm fragen, was er denkt, aber ...Sequence
zu erfüllen, und akzeptieren Sie, dass dies für einige ndarray-Unterklassen eine Lüge ist. Nur auf den selten verwendeten Teilen der Sequence
-Schnittstelle, und Python-Typen sind normalerweise sowieso Lügen ...class multidim_ndarray(ndarray, Sequence):
pass
und machen Sie stattdessen Multi-Dim-Arrays-Instanzen dieser Klasse. Unterklassen sind nicht betroffen, da sie weiterhin von ndarray
erben, nicht von multidim_ndarray
. Natürlich kann ein einzelnes ndarray-Objekt über .resize()
... zwischen 0-d und mehrdimensional wechseln.
ndarray
niemals ein Sequence
.[Das isSequenceType
Ding ist ein bisschen ablenkend. Dies ist eine alte Funktion, die älter ist als abstrakte Basisklassen (die in 2.6 hinzugefügt wurden) und nicht einmal versucht, die für Sequenzen erforderliche detaillierte Schnittstelle festzulegen - sie überprüft lediglich, ob Ihr Typ (1) ein __getitem__
definiert dict
. Offensichtlich wird dies in vielen Situationen die falsche Antwort geben (z. B. alles, was sich wie ein Diktat verhält, aber keines ist!). Wenn man also tatsächlich einen Sequenztyp möchte, dann wird isinstance(obj, Sequence)
einen besseren Job machen, und 2to3 macht das Richtige. Aber es schafft ein Problem für numpy ...]
Vielleicht wäre es möglich, die Python-Leute davon zu überzeugen, eine neue Klasse wie SequenceBase
zu erstellen, die sogar unter der Sequenz liegt und nicht .index
oder .count
garantiert, sondern nur .__len__
und __getitem__
oder so? Es ist alles schön, dass Sequence so etwas wie index
, aber es scheint ein bisschen seltsam, es auf Dinge wie numpy
zu zwingen, indem man es scheinbar so macht, wie sequenzähnliche Dinge vom Typ Ente geschrieben werden sollten. Ist den Python-Leuten bewusst, dass dies etwas problematisch ist?
Ich mag den Vorschlag von @seberg; Wenn Python-Entwickler anderer Meinung sind, würde ich mich für die zweite Kugel von @njsmith entscheiden. Die fehlende Option besteht darin, nur zu sagen, dass ndarrays die Sequenzschnittstelle nicht erfüllen. Nicht optimal, aber besser als die Kugeln 1 und 3 imho.
[Hoppla, die "fehlende Option" war als Option 4 vorhanden, nur irgendwie hat der Markdown-Parser beschlossen, sie auf verwirrende und unlesbare Weise in die vorherige Kugel zu falten. Ich habe den Kommentar bearbeitet, um die Formatierung zu korrigieren.]
Die Hälfte der Typen, die mit Sequence
registriert sind, dh buffer
und xrange
, haben diese Methoden ebenfalls nicht. Mir ist nicht klar, dass dies ebenso erforderliche Methoden der Schnittstelle sind wie bequeme Methoden für diejenigen, die collections.Sequence
als Basisklasse / Mixin verwenden.
@rkern : Guter Fang. Vielleicht besteht die Lösung darin, Sequence.register(np.ndarray)
irgendwo anzurufen. (Dies wäre auch eine Problemumgehung für den ursprünglichen Reporter.)
Wir sollten wahrscheinlich auch irgendwann __reversed__
implementieren ...
@rkern Sie haben Recht, dies wird im PEP als offenes Problem erwähnt: http://www.python.org/dev/peps/pep-3119/#sequences. Seltsam, dass PEPs mit dem Status Final sogar offene Probleme haben können.
Ich denke, der Titel dieses Fehlers ist etwas irreführend, da der Fehler nicht nur unter python3 existiert. Sicher, random.sample(numpy_array)
funktioniert in Python2, aber isinstance(np.array([1]), collections.Sequence)
sollte True
in jedem Python> = 2.6 zurückgeben.
Ich habe diesen Fehler gerade in Python 2.7 mit dem Autopep8-Modul festgestellt. Standardmäßig wurden einige Aufrufe von operator.isSequenceType () in isinstance (x, collection.Sequence) konvertiert. Der Test würde falsch werden, wenn ich eine numpy.ndarray bestanden habe. Dies kann ein sehr hinterhältiger Fehler sein.
Ich bin es auch mit Python 2.7 unter Verwendung des Python-Pillow-Moduls angetroffen. Image.point (lut, mode) ruft isinstance (lut, collection.Sequence) auf, die in der vorherigen Version verwendete operator.isSequenceType ()
Jetzt könnte ein guter Zeitpunkt sein, dies noch einmal zu wiederholen, da die numpy numerischen Skalartypen registriert wurden (# 4547).
Vielleicht besteht die Lösung darin, Sequence.register (np.ndarray) irgendwo aufzurufen.
Ja, das ist ein guter Kompromiss.
Ja, bitte fügen Sie einfach irgendwo Sequence.register(np.ndarray)
.
@mitar Interesse an der Einreichung einer PR?
Sicher. Wohin soll das gehen? In derselben Datei, in der np.ndarray
erstellt wird?
Nur um sicherzugehen, dass wir dies tatsächlich für eine gute Idee halten: Wir fügen gerade eine Abwertung für ein leeres Array hinzu, das False
(# 9718) ist, dh wir entfernen eines der Dinge, die für Sequenzen funktionieren. . Obwohl ich die Kommentare gelesen habe, denke ich, dass die Schlussfolgerung bereits war, dass Array-Skalare nicht funktionieren, also denke ich, dass ein leeres Array Teil dieses gebrochenen Versprechens sein kann ...
Zum späteren Nachschlagen wäre der richtige Ort dafür wahrscheinlich numpy.core.multiarray
:
https://github.com/numpy/numpy/blob/4f1541e1cb68beb3049a21cbdec6e3d30c2afbbb/numpy/core/multiarray.py
OK, ich will das. Wie? So würde ich sie als Methoden implementieren:
def __reversed__(self):
return iter(self[::-1])
def index(self, value) -> int:
return np.in1d(self, value).nonzero()[0]
def count(self, value) -> int:
return (self == value).sum()
# Necessary due to lack of __subclasshook__
collections.abc.register(np.ndarray)
Wir haben festgestellt, dass sich Tensorflow mit der neuesten Version von Tensorflow (2.0) mit Sequence.register(np.ndarray)
schlecht benimmt. Es scheint, als würde irgendwo geprüft, ob der Wert eine Sequenz ist und dann anders verwendet wird als wenn es sich um ein ndarray handelt.
Siehe: https://gitlab.com/datadrivendiscovery/d3m/issues/426
Urkomisch. Ich bin mir ziemlich sicher, dass es die bessere Idee ist, zu testen, ob etwas ein Array ist, da es fast immer der speziell behandelte Fall sein wird.
Wahrscheinlich ist die Reihenfolge der Typprüfungen falsch. Sie sollten zuerst nach ndarray und dann nach Sequenz suchen. Wenn Sie jedoch zuerst nach der Reihenfolge suchen, wird dieser Codeblock jetzt ausgeführt.
@mitar Wir erwägen, dies zu schließen, da sich __contains__
/ operator.in
anders verhält (es rekursiv und nicht für Sequenzen), sodass der API-Vertrag gebrochen wird. Haben Sie einen Anwendungsfall dafür?
Können Sie den API-Vertrag, an den Sie hier denken, näher erläutern? Ich verstehe es nicht genau.
Der Anwendungsfall besteht darin, generischen Code zu schreiben, der weiß, wie man zwischen Dingen konvertiert, z. B. wenn Sie über eine Sequenz iterieren und die Dimension durch Diension zurückerhalten und dann wiederkehren können. Dann kann ich eine Liste von Listen auf die gleiche Weise wie ein 2d ndarray konvertieren, aber es kann auf mehrere Dimensionen verallgemeinern und so weiter. Und ich muss nicht mehr als nur überprüfen, ob es sich um eine Sequenz handelt.
Wie bereits erwähnt, gibt es einige Probleme beim Anzeigen von Arrays als verschachtelte Python-Sequenzen. __contains__
ist die offensichtlichste, die andere ist, dass 0-D-Arrays definitiv keine verschachtelten Sequenzen sind. Es gibt auch Feinheiten wie eine Dimension der Länge 0, und im Allgemeinen bedeutet arr[0] = 0
nicht, dass arr[0] == 0
, da arr[0]
selbst ein beliebiges Array sein kann (was besser geschrieben wäre als arr[0, ...]
. Persönlich finde ich die Interpretation der "verschachtelten Sequenz" nett, aber weniger nützlich als wir denken. (Dh ich iteriere selten ein Array als for col in array
und selbst wenn ich es tue, ich Ich hätte nichts dagegen, for col in array.iter(axis=0)
schreiben
Daher neige ich dazu, das "Array ist eine Sequenz" als eine leicht problematische Analogie zu sehen (was nicht bedeutet, dass es nicht ueful sein kann, gebe ich zu).
Was auch immer der Anwendungsfall ist, ich bin gespannt, ob es nicht besser wäre, ein neues ABC wie einen neuen "ElementwiseContainer" zu erkunden. Eine, die dem Benutzer auch mitteilt, dass +
und ==
usw. für jedes Element funktionieren und dass er im Gegensatz zu Python-Sequenzen nicht +
einer Verkettung von +
ist nicht Teil der Sequenz ABC, aber es fühlt sich in Python natürlich an.
Gehe nur vorbei -
Ich habe letzte Woche an Python-ideas geschrieben, weil ich festgestellt habe, dass Pythons collections.abc.Sequence
keine __eq__
und andere Vergleiche implementiert - obwohl es alle anderen Methoden gibt, um diese zu implementieren, damit sich Sequence wie Listen und verhält Tupel. (Dieser Mail-Thread hat mich zu diesem Problem geführt).
Ich schlug vor, dort __eq__
hinzuzufügen, aber es würde offensichtlich dazu führen, dass diese Sequenzen vom Verhalten von Numpy.array abweichen.
Was ist mit mehr Formalisierung in Python, was sind "Sequenzen" und dann Delegieren dieser Dinge, die als Spezialfälle auseinander gehen würden - bis zum Hinzufügen eines collections.abc.ComparableSequence
dort? (und da oben +
für die Verkettung erwähnt wurde, könnte ein anderer Name "Sequenzen implizieren, deren Vergleich zu einem einzelnen Bool führt und sich als Skalare für die Verkettung und Multiplikation mit dem Skalar verhalten" - dh das Python-Verhalten für die +
und *
in Liste und Tupel). Daher könnten die Spezifikationen für die Sequenz so formalisiert werden, dass mindestens 1D-Numpy-Arrays genau dazu passen.
Diese Formalisierung einer Python-Sequenz könnte auch bei anderen Abweichungen helfen, wie der oben unter https://github.com/numpy/numpy/issues/2776#issuecomment -330865166 erwähnten.
Ich fühle mich zwar nicht motiviert genug, diesen Weg alleine zu gehen - aber wenn dies Sinn macht, würde ich gerne helfen, einen PEP zu schreiben und ihn durchzusetzen. (Ich wollte nur überprüfen, warum die Sequenz kein __eq__
, und möglicherweise eine PR dafür haben, als ich dies ansprach.)
@jsbueno mein Problem ist, dass ich nicht wirklich sehe, welche zusätzliche oder dazwischen liegende Definition für Benutzer von ndarray
tatsächlich hilfreich wäre. Das Beste, was ich mir vorstellen kann, ist ein Collection
mit count()
und index()
, aber ist das nützlich? Alles andere wäre ein ABC für Dinge, von denen Python selbst wenig oder gar kein Konzept hat.
Ich denke, SymPy hat es tatsächlich besser gemacht. Es durchläuft alle Elemente seiner Matrizen, was es zumindest zu einem Collection
.
Ich bezweifle, dass wir viel dagegen tun können, und ich bin mir nicht einmal sicher, ob die SymPy-Iteration aller Elemente sehr nützlich (und intuitiv) ist, aber zumindest stimmt die Iteration aller Elemente mit __contains__
überein. Beachten Sie, dass dies auch bedeutet, dass len(Matrix)
die Anzahl der Elemente ist und _not_ Matrix.shape[0]
!
Was sind numpy Arrays, abgesehen von 1-D-Arrays, mit dem Risiko, viel von oben zu wiederholen?:
Container
: von Elementen: heavy_check_mark:Sized
+ Iterable
von Subarrays (wenn nicht 1-D): Frage:Reversible
: Wir könnten das einfach umsetzen, keine Sorge. :Frage:count()
und index()
: können für Elemente implementiert Sequence
: Mismatch zwischen Subarray iterable und Elementbehälter: x:So stoßen selbst einige der grundlegendsten Eigenschaften aufeinander. NumPy könnte ein Container
der weiß, wie man .index()
und .count()
, dh ein Sequence
aber ohne den Teil Iterable
. Es ist zwar unabhängig ein Iterable
, aber von Subarrays .
Und wenn das wie ein verwirrendes Durcheinander erscheint, stimme ich zu, aber ich denke, dass es beabsichtigt ist. Die einzig wahre Lösung wäre, entweder den SymPy-Pfad zu beschreiten oder zunächst einfach kein Iterable
zu sein. (Wir können den SymPy-Pfad nicht beschreiten, und ich bezweifle, dass die Abwertung von __iter__
eine Chance hat.)
Persönlich gehe ich davon aus, dass 1-D-Arrays, abgesehen von Array-Likes, im Vergleich zu Python-Sammlungen einfach ganz andere Bestien sind. Wenn Sie das Iterationsverhalten berücksichtigen, benötigen Sie ein MultidimensionalCollection
, um die Nichtübereinstimmung zwischen __contains__
und __iter__
zu signalisieren (aber ist das nützlich?).
Wenn ich über das hinaus schaue, was derzeit durch Sequence
, möchte ich noch einmal betonen, dass ich denke, dass die ElementwiseCollection
(Operatoren sind eher elementweise Operatoren als Containeroperatoren, z. B. +
) die meisten sind Definieren der Charakteristik von Numpy-Arrays und allen Array-Likes im Allgemeinen (siehe Array-Programmierung). Es ist jedoch auch ein Konzept, das Python selbst völlig fremd ist - und manchmal im Widerspruch dazu steht.
Das einzige wäre, eindimensionale Arrays und nur eindimensionale Arrays als Sequenzen zu markieren, da sie nicht die Nichtübereinstimmung von Subarray und Element aufweisen. Zu diesem Zeitpunkt ist __eq__
natürlich nicht für sie definiert, und __nonzero__
ist nicht ähnlich wie typische Python-Sequenzen definiert.
Vielen Dank für die Antwort, und ich entschuldige mich noch einmal für das Springen in den 8 Jahre langen Wagen hier. Mit Ihrem Kommentar, ein paar Stunden nach dem letzten E-Mail-Austausch und dem Chatten mit einem anderen Freund in der Mitte, stimme ich zu, dass die meisten dieser Dinge besser so bleiben, wie sie sind. Irgendwann in der Zukunft kann Python eine formellere Definition der Sequenz wählen als "was auch immer collection.abc.Sequence jetzt implementiert".
Nachdem ich Ihre obigen Kommentare gelesen habe, möchte ich nur hinzufügen, dass ich denke, dass den Eigenschaften, die Sie als "Was macht eine Python-Sequenz aus?" Aufgeführt haben, das wichtigste Merkmal fehlt, das ndarrays für mich Sequenzen wie Listen und Tupel ähneln lässt: einen zusammenhängenden Index. Raum, der alle einzelnen Elemente ansprechen kann. Aber ich denke nicht, dass die Formalisierung eines ABC für diesen Zweck von praktischem Wert wäre, weder bei der Codierung noch bei statischen Hinweisen.
@seberg Das ist eine großartige Zusammenfassung.
In diesem Problem geht es anscheinend um die Verwendung von ndarray
in Kontexten, in denen Sequence
oder Iterable
oder Container
erwartet werden. Ein einfacher Ansatz wäre, Mitglieder auf ndarray
, die billige Ansichten enthüllen, die versprechen und die entsprechende Schnittstelle bereitstellen und auf isinstance
Schecks reagieren. Zum Beispiel:
class ndarray(Generic[T]):
def as_container(self) -> Container[T]:
if self.ndim == 0:
raise ValueError
return ContainerView(self) # correctly answers __len__, __iter__ etc.
def as_subarray_iterable(self) -> Iterable[np.ndarray[T]]:
if self.ndim <= 1:
raise ValueError
return SubarrayIterableView(self)
def as_scalar_sequence(self) -> Sequence[T]:
if self.ndim != 1:
raise ValueError
return ScalarView(self)
def as_subarray_sequence(self) -> Sequence[np.ndarray[T]]:
if self.ndim <= 1:
raise ValueError
return SubarraySequenceView(self) # this view has to reinterpret __contains__ to do the expected thing.
Anstatt ndarray
versprechen, für alle alles zu sein, fragt der Benutzer, was er braucht, und wenn ndarray
es bereitstellen kann, geschieht dies auf die billigste Art und Weise. Wenn dies nicht möglich ist, wird eine Ausnahme ausgelöst. Dies vereinfacht den Benutzercode, indem die Überprüfung des ndim
, die der Benutzer durchführen sollte (insbesondere bei Verwendung von Typanmerkungen), in ndarray
.
Sollte diese letzte Anmerkung Sequence
und nicht Iterable
?
@ Eric-Wieser Yup! Vielen Dank. Was sind deine Gedanken?
Nun, as_subarray_sequence
ist praktisch list(arr)
:)
@ eric-wieser Ja, ich dachte, es wäre billiger, eine Ansicht bereitzustellen, aber ich habe keine Ahnung.
Nun, list(arr)
erzeugt nur len(arr)
Ansichten, die Sie sowieso produzieren würden, wenn ich Sie iterieren würde.
Ich denke immer noch, dass wir uns zu sehr darauf konzentrieren, was getan werden kann, und nicht genug darauf, was die Probleme derzeit sind. Insbesondere sind alle oben angegebenen Methoden sehr einfach zu implementieren, wenn Sie wissen, dass Sie ein ndarray-ähnliches haben (ich bin nicht der Meinung, dass 0-D-Arrays keine Container sind). Sie wären also nur dann nützlich, wenn es ein standardisiertes ABC für sie gäbe, und in diesem Fall würde es auch ausreichen, zu definieren, dass die grundlegende Indizierung numpy-kompatibel ist und möglicherweise die Eigenschaft .flat
.
Das ursprüngliche Problem ( random.sample
funktioniert nicht mehr) scheint aufgrund der verstrichenen Zeit ziemlich irrelevant zu sein. Ja, es ist leicht ärgerlich, aber möglicherweise sogar zum Besseren, da der Benutzer entweder erwarten kann, dass die Subarrays oder die Elemente ausgewählt werden.
Ich bin sicher , dass wir eine Ente-Eingabe Code brechen. Einige Probleme treten wahrscheinlich bei der Serialisierung auf (ich habe keine Beispiele zur Hand). Und viele solcher Codes haben kein Problem damit, isinstance
Schecks für ABC
, aber sie hassen es, speziell nach np.ndarray
suchen. Ich sehe nicht ein, wie das Hinzufügen von Methoden zu ndarray dabei helfen würde. Wir würden ein neues ABC
benötigen, wahrscheinlich mit etwas mehr als der .ndim
-Eigenschaft und möglicherweise der Verankerung der Iteration im Stil verschachtelter Sequenzen.
Methoden wie die oben genannten mögen als Verbraucherprotokoll sinnvoll sein, um mit jedem Array zu arbeiten, aber ist das das Problem, das wir zu lösen versuchen :)? Sie scheinen nicht wie Dinge zu sein, die typische Python-Sequenzen enthüllen möchten.
@ Eric-Wieser
Sie haben natürlich Recht, aber Sie können möglicherweise nicht die gesamte Sequenz durchlaufen. Sie können nur einige Elemente auswählen.
@seberg
Ich denke immer noch, dass wir uns zu sehr darauf konzentrieren, was getan werden kann, und nicht genug darauf, was die Probleme derzeit sind
Ich stimme mit Ihnen ein. Welche Art von Problemen stellen Sie sich vor? Ich stelle mir vor, dass ich, wenn numpy 1.10 mit Typen herauskommt, manchmal ein eindimensionales numpy-Array als Sequenz verwenden möchte. Wenn ich das derzeit tun möchte, muss ich:
cast
an, um mypy mitzuteilen, dass es sich tatsächlich um eine Sequenz handelt.Deshalb möchte ich eine Methode bereitstellen, um dies automatisch zu tun. Ich hasse auch große Schnittstellen, aber es scheint mir, dass diese Art von Methoden oder nackten Funktionen immer häufiger vorkommen werden, wenn sich Typanmerkungen durchsetzen. Was denken Sie?
(Ich bin nicht der Meinung, dass 0-D-Arrays keine Container sind).
Ich habe keine Ahnung, aber derzeit erhöhen Sie __len__
für diese, so dass es scheint, dass sie nicht wie Container funktionieren. Ich denke, es wäre hilfreich für mypy, einen Fehler zu melden, wenn Sie ein 0-D-Array an eine Funktion übergeben, die einen Container akzeptiert. Es wird nicht abgefangen, wenn Sie 0-D-Arrays-Container erstellen.
Wir würden ein neues ABC benötigen, wahrscheinlich mit wenig mehr als der .ndim-Eigenschaft und möglicherweise der Iteration im Stil verschachtelter Sequenzen.
Ich wollte das nicht in meinen Vorschlag aufnehmen, aber ich denke, das ist sowieso der Weg dorthin. Ich bin ein begeisterter Benutzer der wunderbar gestalteten JAX-Bibliothek. Ich stelle mir vor, dass in Zukunft numpy.ndarray
und jax.numpy.ndarray
(die Unterklassen haben) beide von irgendeiner abstrakten NDArray
erben werden. Sie könnten viel mehr als ndim
. Im Idealfall wäre es mindestens NDArray(Generic[T])
, und möglicherweise hat das Ereignis auch die Form oder die Anzahl der Dimensionen. Es könnte __eq__
, das NDArray[np.bool_]
. Du weißt es wahrscheinlich besser als ich :)
Vor ein paar Jahren habe ich nach diesem Problem gesucht, um vorzuschlagen, dass numpy.array
von collections.Sequence
erben sollte, aber jetzt finde ich die Argumente (insbesondere Ihre !!) in diesem Thread sehr überzeugend. Numpy Arrays sind keine wirklichen Sequenzen, und es scheint, als würde es mehr Schaden als Nutzen verursachen, wenn man sie beschuht. Warum lassen Sie sie nicht einfach ihr eigenes Ding sein und zwingen die Benutzer, die gewünschte Schnittstelle explizit anzufordern?
Und viele solcher Codes haben kein Problem mit der Verwendung von Instanzprüfungen für ABCs.
Nun, da Sie das erwähnen, sollten vielleicht alle meine vorgeschlagenen Methoden Ansichten zurückgegeben haben. Auf diese Weise können sie die Instanzprüfungen korrekt beantworten.
Methoden wie die oben genannten mögen als Verbraucherprotokoll sinnvoll sein, um mit jedem Array zu arbeiten, aber ist das das Problem, das wir zu lösen versuchen :)? Sie scheinen nicht wie Dinge zu sein, die typische Python-Sequenzen enthüllen möchten.
Ich stimme definitiv zu, dass die Antwort darauf von den Problemen abhängt, die wir zu lösen versuchen. Nachdem ich die Typ Annotation Kool Aid getrunken habe, bin ich daran interessiert, prägnanten Numpy-Code zu schreiben, der mypy übergibt, ohne den Code mit # type: ignore
verunreinigen. Welche Probleme haben Sie im Sinn?
Tipphinweise und Interop mit anderen Array-ähnlichen Objekten sind wahrscheinlich eine gute Motivation. Ich könnte vorschlagen, eine neue Ausgabe oder einen Mailinglisten-Thread zu öffnen. Im Moment bin ich mir nicht sicher, woran ich hier am besten denken soll. Das Tippen bildet sich. Vielleicht klärt das dann einige Dinge.
Hilfreichster Kommentar
Ja, bitte fügen Sie einfach irgendwo
Sequence.register(np.ndarray)
.