Numpy: ndarray sollte von collection.abc.Sequence abgeleitet sein?

Erstellt am 1. Dez. 2012  ·  49Kommentare  ·  Quelle: numpy/numpy

@ 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

Hilfreichster Kommentar

Ja, bitte fügen Sie einfach irgendwo Sequence.register(np.ndarray) .

Alle 49 Kommentare

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

  • Verwerfen Sie die inkompatiblen Verwendungen in ndarray-Unterklassen, entfernen Sie sie schließlich und ersetzen Sie sie durch 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 ...
  • Erklären Sie ndarray und seine Unterklassen, um die Definition von 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 ...
  • Jiggen Sie unsere Vererbungshierarchie neu, um Funktionalität und Unsinn der abstrakten Basisklasse zu trennen. Tun
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.

  • Akzeptiere, dass 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:

  • Überprüfen Sie, ob es eindimensional ist, und
  • Rufen Sie 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.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen