Numpy: ndarray doit dériver de collections.abc.Sequence?

Créé le 1 déc. 2012  ·  49Commentaires  ·  Source: numpy/numpy

@juliantaylor a soulevé ce problème dans un problème de pandas.

L'exemple du 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).

Cela se produit sur 3.3 avec 1.7.0rc1.dev-3a52aa0, et sur 3.2 avec 1.6.2.
2.7 n'est bien sûr pas affecté.

Le code pertinent de 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).")

Je n'ai pas pu grep un autre emplacement dans le stdlib avec un test similaire, mais lib2to3
a montré une équivalence supposée:

lib2to3/fixes/fix_operator.py
5:operator.isSequenceType(obj)   -> isinstance(obj, collections.Sequence)

dans 2,7

In [6]: operator.isSequenceType(np.array([1]))
Out[6]: True

mais en 3.3 / 3.2

>>> isinstance(np.array([1]), collections.Sequence)
False

Commentaire le plus utile

Oui, veuillez simplement ajouter Sequence.register(np.ndarray) quelque part.

Tous les 49 commentaires

Python 3.x effectue simplement une vérification plus stricte dans random.sample que Python 2.x. Sur 2.x, numpy n'est pas non plus une sous-classe Sequence (ndarray n'a pas index méthodes count ou __reversed__ ). Je pense donc que vous pouvez considérer cela comme une mauvaise utilisation de random.sample ou une rupture de compatibilité avec Python 3.x.

Très bien, mais cela dit, nous pourrions facilement _make_ ndarray a Sequence,
puisque toutes ces méthodes ont du sens et seraient simples à
mettre en place. En fait, il suffirait d'en hériter, puisque Sequence
fournit toutes les méthodes manquantes sous forme de mixins.
Le 2 décembre 2012 à 13h30, "Ralf Gommers" [email protected] a écrit:

Python 3.x effectue simplement une vérification plus stricte dans random.sample que
Python 2.x. Sur 2.x, numpy n'est pas non plus une sous-classe de séquence (ndarray n'a pas
index, comptage ou méthodes inversées ). Donc je pense que vous pouvez considérer cela comme
soit une mauvaise utilisation de random.sample, soit une rupture de compatibilité ascendante
Python 3.x.

-
Répondez directement à cet e-mail ou consultez-le sur Gi tHubhttps: //github.com/numpy/numpy/issues/2776#issuecomment -10929601.

J'aurais dit la même chose, sans l'exemple 2to3 qui rend cela plus subtil.
l'index et le décompte ne sont pas nécessaires, je crois: Lien ,
Toutes les méthodes abstraites pour Sequence sont déjà implémentées, les autres ont des implémentations par défaut.

Le problème est que MutableSequence est en fait plus correct, et insert n'est pas implémenté.

n'oubliez pas les tableaux 0-d, je ne suis pas sûr de ce qui se passe avec eux en ce moment, mais ils ne sont pas vraiment une séquence, n'est-ce pas?

Hmm, Sequence est destiné aux objets immuables, certaines des méthodes de MutableSequence (extend, pop) n'ont pas de sens. Donc oui, nous pourrions ajouter ces 3 méthodes mais cela ne semble pas tout à fait correct.

Il me semble qu'il n'y a vraiment aucune raison pour que random.sample nécessite une instance Sequence .

__setitem__ est implémenté, mais pas __delitem__ , alors peut-être SomewhatMutableSequence ?

Il est logique que vous interprétiez l'interface comme "une séquence devrait avoir tout cela, mais certains peuvent
have terrible O () ", c'est pourquoi ils proposent des implémentations naïves de certaines méthodes.
Ce n'est certainement pas la sémantique de insert , pop qui n'est pas claire dans le contexte d'un ndarray.
Cependant, je ne suis pas sûr de la bonne chose concernant l'itération sur un tableau 0-d.
On pourrait affirmer qu'offrir une méthode __iter__ qui lève simplement un TypeError plutôt que
StopIteration est de toute façon une violation de la saisie de canard.

edit : Bien que je sois sûr que ce n'était pas une décision imprudente.

ndarray pourrait simplement être une séquence, cela ne veut pas dire qu'il doit être immuable.

Btw. l'implémentation de la liste CPython ne prend pas non plus en charge l'insertion, le pop et l'extension efficaces, mais c'est toujours une MutableSequence

ndarray ne peut pas prendre en charge l'insertion / pop / extend sur place (les ndarray ont une taille fixe), donc bien qu'il s'agisse d'une séquence mutable, ce n'est tout simplement pas un Python MutableSequence (et ne le sera jamais). Il peut et doit cependant prendre en charge l'interface Sequence .

Ce serait bien si random.sample ne le vérifiait pas, mais à y regarder de plus près, cela a une raison plausible - il a un certain nombre d'implémentations différentes pour différents types d'arguments d'entrée, il a donc besoin d'un moyen pour les distinguer. Il ne peut pas simplement commencer à indexer et espérer le meilleur. Peut-être que nous pourrions déposer un bogue et essayer de les convaincre de se rabattre sur l'implémentation de la séquence par défaut pour les types non reconnus, mais le premier qui pourrait aider est 3.4 ...

Le point concernant les tableaux 0-d est bon, cependant; Les tableaux 0-d ne prennent pas en charge l'interface Sequence (ils ne sont même pas Iterable ). Mais pour les besoins de Python, ce n'est pas trop terrible s'ils mentent sur le fait d'être Sequence s et qu'ils attendent ensuite que l'accès réel génère une erreur - la saisie de canard signifie que vous pouvez toujours échouer si vous le souhaitez :-). Il est probablement possible d'une manière ou d'une autre de faire réussir isinstance(a, Sequence) pour les tableaux multidimensionnels et échouer pour les tableaux 0-d; si nous pouvons y arriver, cool. Mais même si nous ne pouvons pas, la meilleure chose à faire est probablement de transformer les ndarray en Sequence s.

Notez que MaskedArray a déjà une méthode count , donc en ajouter une dans ndarray qui fait quelque chose de différent cassera cela.

Les tableaux 0-D sont mieux considérés comme des scalaires avec quelques méthodes pratiques (du moins c'est ce que je pense d'eux); en plus de ne pas être itérables, ils ne sont pas non plus indexables, ce qui est encore plus étrange si vous les considérez comme des tableaux. Donc, rendre les tableaux 0-D incohérents d'une autre manière n'est pas un gros problème à mon avis.

@njsmithlen(population) , puis une conversion en liste. http://hg.python.org/cpython/file/22d891a2d533/Lib/random.py

Les types Pandas Series et DataFrame ont également des méthodes de comptage incompatibles et un attribut d'index.

@rgommers : Hmm, vous avez raison, j'ai été induit en erreur par le message d'erreur, et je pensais qu'il acceptait également les entiers comme raccourci pour range() , ce qui n'est pas le cas. Même dans ce cas, ils souhaitent définir un comportement différent pour les ensembles, les séquences et les mappages. Peut-être pouvons-nous les convaincre qu'ils devraient passer à

if isinstance(population, _Set):
    population = tuple(population)
if isinstance(population, _Mapping):
    raise Blarrrgh()
# Otherwise assume that we have a sequence and hope

C'est également un bon point concernant les sous-classes ndarray existantes. Il ne semble pas y avoir de moyen de dire que ndarray est un Sequence mais ses sous-classes ne le sont pas :-(. Alors quelle option est la moins mauvaise, étant donné que certaines de ces sous-classes ne peuvent pas satisfaire le Sequence Interface

  • Dépréciez les utilisations incompatibles dans les sous-classes ndarray, puis supprimez-les et remplacez-les par des versions compatibles Sequence . Cela semble faisable pour les méthodes count , mais changer le nom de Series.index serait extrêmement perturbateur pour les pandas. (DataFrame n'est pas une sous-classe de ndarray, donc techniquement, ce n'est pas pertinent, sauf que je suppose que la série et le DataFrame doivent être synchronisés.) Je suppose que nous pouvons demander à @wesm ce qu'il pense mais ...
  • Allez-y et déclarez ndarray et ses sous-classes pour satisfaire la définition Sequence , et acceptez que pour certaines sous-classes de ndarray, ce sera un mensonge. Seulement sur les parties rarement utilisées de l'interface Sequence , cependant, et les types Python sont généralement des mensonges de toute façon ...
  • Re-jigger notre hiérarchie d'héritage pour séparer la fonctionnalité et le non-sens de la classe de base abstraite. Faire
class multidim_ndarray(ndarray, Sequence):
  pass

et créez à la place des instances de tableaux à plusieurs dimensions de cette classe. Les sous-classes ne sont pas affectées car elles continuent d'hériter de ndarray , et non de multidim_ndarray . Bien sûr, un seul objet ndarray peut faire la transition entre 0-d et multidimensionnel via .resize() ...

  • Acceptez que ndarray ne sera jamais un Sequence .

[Le truc isSequenceType est un peu une distraction. C'est une ancienne fonction qui est antérieure à l'existence des classes de base abstraites (qui ont été ajoutées en 2.6), et n'essaye même pas de définir l'interface détaillée requise des séquences - elle vérifie simplement que votre type (1) définit un __getitem__ , (2) n'est pas un dict intégré. Évidemment, cela donnera la mauvaise réponse dans de nombreuses situations (par exemple, tout ce qui agit comme un dict mais n'en est pas un!). Donc, si l'on veut réellement un type de séquence, alors isinstance(obj, Sequence) va faire un meilleur travail, et 2to3 fait ce qu'il faut. Mais cela crée un problème pour numpy ...]

Peut-être serait-il possible de convaincre les gens de python de créer une nouvelle classe comme SequenceBase qui est même en dessous de Sequence et ne garantit pas .index ou .count , mais seulement .__len__ et __getitem__ ou autre? C'est bien beau que Sequence ait quelque chose comme index , mais il semble un peu étrange de le forcer sur des choses comme numpy en faisant apparemment en sorte que la séquence comme les choses devrait être typée canard. Les gens de Python sont-ils conscients que c'est quelque peu problématique?

J'aime la proposition de @seberg; si les développeurs de Python ne sont pas d'accord, j'opterais pour la deuxième puce de @njsmith. L'option manquante est simplement de dire que les ndarrays ne satisfont pas l'interface Sequence. Pas optimal, mais mieux que les balles 1 et 3 à mon humble avis.

[Oups, "l'option manquante" était là en tant qu'option 4, mais d'une manière ou d'une autre, l'analyseur de démarques a décidé de la replier dans la puce précédente d'une manière déroutante et illisible. J'ai modifié le commentaire pour corriger la mise en forme.]

La moitié des types enregistrés avec Sequence , c'est- buffer dire xrange , n'ont pas non plus ces méthodes. Il n'est pas clair pour moi que ce sont autant des méthodes requises de l'interface que des méthodes pratiques pour ceux qui utilisent collections.Sequence comme classe de base / mixin.

@rkern : Bonne prise. Alors peut-être que la solution est simplement d'ajouter un appel à Sequence.register(np.ndarray) quelque part. (Ce serait également une solution de contournement pour le journaliste d'origine.)

Nous devrions probablement implémenter __reversed__ à un moment donné également ...

@rkern vous avez raison, ceci est mentionné comme un problème ouvert dans le PEP: http://www.python.org/dev/peps/pep-3119/#sequences. Il est étrange que les PEP avec le statut Final puissent même avoir des problèmes en suspens.

Je pense que le titre de ce bogue est un peu trompeur, car le bogue n'existe pas uniquement sous python3. Bien sûr, random.sample(numpy_array) fonctionne en python2, mais isinstance(np.array([1]), collections.Sequence) devrait renvoyer True dans n'importe quel python> = 2.6.

Je viens de rencontrer ce bogue dans Python 2.7 en utilisant le module autopep8. Par défaut, il a converti certains des appels operator.isSequenceType () en isinstance (x, collections.Sequence). Le test deviendrait False lorsque je passais dans un numpy.ndarray. Cela peut être un bug très sournois.

Je viens de le rencontrer également avec Python 2.7, en utilisant le module python-oreiller. Image.point (lut, mode) appelle isinstance (lut, collections.Sequence), la version précédente utilisait operator.isSequenceType ()

Le moment est peut-être venu de revisiter cela puisque les types scalaires numériques numpy ont été enregistrés (# 4547),

Alors peut-être que la solution est simplement d'ajouter un appel à Sequence.register (np.ndarray) quelque part.

Oui, c'est un bon compromis.

Oui, veuillez simplement ajouter Sequence.register(np.ndarray) quelque part.

@mitar est-il intéressé à soumettre un PR?

Sûr. Où cela devrait-il aller? Dans le même fichier où np.ndarray est créé?

Juste pour être sûr que nous pensons vraiment que c'est une bonne idée: nous sommes en train d'ajouter une obsolescence pour un tableau vide étant False (# 9718), c'est-à-dire que nous supprimons l' une des choses qui fonctionne pour les séquences) . En lisant les commentaires, je pense que la conclusion était déjà que les scalaires de tableau ne fonctionneront pas, donc je suppose qu'un tableau vide peut faire partie de cette promesse non tenue ...

Pour référence future, le bon endroit pour le faire serait probablement dans numpy.core.multiarray :
https://github.com/numpy/numpy/blob/4f1541e1cb68beb3049a21cbdec6e3d30c2afbbb/numpy/core/multiarray.py

OK je veux ça. Comment? Ce serait ainsi que je les implémenterais en tant que méthodes:

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)

Nous avons découvert qu'avec la dernière version de Tensorflow (2.0), le fait d'avoir Sequence.register(np.ndarray) fait que Tensorflow se comporte mal. Il semble qu'il vérifie quelque part si value est une séquence, puis utilise est différent de celui d'un ndarray.

Voir: https://gitlab.com/datadrivendiscovery/d3m/issues/426

Hilarant. Je suis à peu près sûr que tester si quelque chose est un tableau est la meilleure idée, car ce sera presque toujours le cas spécialement traité.

L'ordre des vérifications de type est probablement incorrect, il devrait d'abord vérifier ndarray, puis la séquence. Mais si vous vérifiez d'abord la séquence, alors maintenant ce bloc de code s'exécute.

@mitar Nous envisageons de fermer ceci parce que __contains__ / operator.in se comporte différemment (il se répète, et ce n'est pas le cas pour les séquences), donc il rompt le contrat de l'API. Avez-vous un cas d'utilisation pour cela?

Pouvez-vous nous expliquer le contrat d'API que vous avez en tête ici. Je ne comprends pas exactement.

Le cas d'utilisation est l'écriture de code générique qui sait convertir entre les choses, comme si vous pouvez itérer sur une séquence et récupérer dimension par dimension, puis récurer. Ensuite, je peux convertir une liste de listes de la même manière qu'un ndarray 2D, mais cela peut se généraliser à plusieurs dimensions et ainsi de suite. Et je n'ai pas à vérifier plus que juste qu'il s'agit d'une séquence.

Comme mentionné, il y a quelques problèmes pour voir les tableaux comme des séquences python imbriquées. __contains__ est la plus évidente, l'autre est que les tableaux 0-D ne sont certainement pas des séquences imbriquées. Il existe également des subtilités, telles qu'une dimension de longueur 0, et généralement arr[0] = 0 ne signifie pas que arr[0] == 0 , puisque arr[0] peut être un tableau arbitraire lui-même (qui serait mieux orthographié comme arr[0, ...] . Personnellement, je pense que l'interprétation de la "séquence imbriquée" est agréable, mais moins utile que ce que nous avons tendance à penser (c'est-à-dire que j'itère rarement un tableau comme for col in array et même si je le fais, cela ne me dérangerait pas d'écrire for col in array.iter(axis=0)

J'ai donc tendance à voir le "tableau est une séquence" comme une analogie légèrement problématique (ce qui ne veut
Cependant, quel que soit le cas d'utilisation, je suis curieux de savoir s'il ne serait pas préférable d'explorer un nouvel ABC, tel qu'un nouveau "ElementwiseContainer". Celui qui indique également à l'utilisateur que + et == , etc. fonctionneront sur chaque élément , et que, contrairement aux séquences Python, ils ne devraient pas s'attendre + ce que + ne fait pas partie de la séquence ABC, mais cela semble naturel en Python).

Juste en passant -
J'ai écrit à Python-ideas la semaine dernière parce que j'ai noté que collections.abc.Sequence de Python n'implémente pas __eq__ et d'autres comparaisons - même s'il a toutes les autres méthodes pour implémenter celles-ci pour que Sequence se comporte comme des listes et tuples. (ce fil de discussion m'amène à ce problème).

Je proposais d'ajouter __eq__ ici, mais cela ferait évidemment diverger ces séquences du comportement de Numpy.array.

Qu'en est-il de formaliser davantage, en Python, que sont les «séquences» et de déléguer ensuite ces choses qui divergeraient en tant que cas spécialisés - au point d'y ajouter un collections.abc.ComparableSequence ? (et puisque le + pour la cancaténation a été mentionné ci-dessus, peut-être un autre nom qui impliquerait "des séquences dont la comparaison aboutit à un seul booléen, et se comportent comme des scalaires pour la concaténation et se multiplient par scalaire" - ie - le comportement de Python pour les + et * dans la liste et les tuples). Par conséquent, les spécifications sur la séquence pourraient être formalisées de manière à ce qu'au moins les tableaux numpy 1D correspondent exactement.

Cette formalisation sur ce qu'est une séquence Python pourrait également aider avec d'autres divergences, comme celle mentionnée dans https://github.com/numpy/numpy/issues/2776#issuecomment -330865166 ci-dessus.

Je ne me sens pas assez motivé pour s'engager seul dans cette voie, mais si cela a du sens, je serais heureux d'aider à rédiger un PEP et à le faire avancer. (Je voulais juste vérifier pourquoi la séquence n'a pas créé de __eq__ , et peut-être avoir un PR pour cela quand j'ai évoqué cela)

@jsbueno, mon problème est que je ne vois pas vraiment quelle définition supplémentaire ou ndarray . Le mieux auquel je puisse penser est un Collection qui a count() et index() , mais est-ce utile? Tout le reste serait un ABC pour des choses dont Python lui-même a peu ou pas de concept.

Je pense que SymPy a en fait plus raison. Il parcourt tous les éléments de ses matrices, ce qui en fait au moins un Collection .
Maintenant, je doute que nous puissions faire grand-chose à ce sujet, et je ne suis même pas sûr que l'itération SymPy de tous les éléments soit super utile (et intuitive), mais au moins l'itération de tous les éléments est cohérente avec __contains__ . Notez que cela signifie également que len(Matrix) est le nombre d'éléments, et _pas_ Matrix.shape[0] !

Avec le risque de répéter beaucoup d'en haut, mis à part les tableaux 1-D, que sont les tableaux numpy?:

  • Container : des éléments: heavy_check_mark:
  • Sized + Iterable de sous -
  • Reversible : nous pourrions simplement implémenter cela, pas de soucis. :question:
  • count() et index() : peuvent être implémentés pour les éléments (: heavy_check_mark :)
  • Sequence : Non - concordance entre le éléments : x:

Ainsi, même certaines des propriétés les plus fondamentales s'affrontent. NumPy pourrait être un Container qui sait faire .index() et .count() , soit un Sequence mais sans la partie Iterable . Alors que c'est indépendamment un Iterable , mais de sous-tableaux .
Et si cela semble être un désordre déroutant, alors je suis d'accord, mais je pense que c'est par conception. La seule vraie solution serait soit d'emprunter le chemin SymPy, soit de ne pas être un Iterable pour commencer. (nous ne pouvons pas suivre le chemin SymPy, et je doute que déprécier __iter__ ait une chance.)

Personnellement, je m'attends à ce que les tableaux 1-D mis à part, les tableaux-like soient simplement des bêtes très différentes des collections Python. Lors de l'examen du comportement d'itération, vous auriez besoin d'un MultidimensionalCollection pour signaler spécifiquement le décalage entre __contains__ et __iter__ (mais est-ce utile?).

En regardant au-delà de ce qui est actuellement défini par Sequence , je répéterai que je pense que les ElementwiseCollection (les opérateurs sont des opérateurs élémentaires plutôt que des opérateurs de conteneur, par exemple + ) est le plus définition des caractéristiques des tableaux numpy et de tous les tableaux similaires en général (voir programmation de tableaux). C'est aussi un concept complètement étranger - et parfois en contradiction avec - Python lui-même, cependant.

La seule chose à faire serait de marquer les tableaux à une dimension, et seulement les tableaux à une dimension comme des séquences, car ils n'ont pas le décalage entre sous-tableau et élément. À ce stade, oui, __eq__ n'est bien sûr pas défini pour eux, et __nonzero__ n'est pas défini de la même manière que les séquences Python typiques.

Merci pour la réponse et je m'excuse encore d'avoir sauté dans le wagon de 8 ans ici. Avec votre commentaire, quelques heures après le dernier échange de courriels, et en discutant avec un autre ami au milieu, je suis d'accord que la plupart de ces choses sont mieux laissées telles quelles. Dans le futur, Python pourra choisir d'avoir une définition plus formelle de Sequence que "tout ce que collections.abc.Sequence implémente maintenant".

J'ajouterai simplement, après avoir lu vos commentaires ci-dessus, que je pense que les caractéristiques que vous avez énumérées comme "ce qui fait une séquence Python" manquent de la caractéristique la plus importante qui fait que les ndarrays ressemblent à des séquences comme des listes et des tuples pour moi: avoir un index contigu - espace qui peut traiter tous les éléments individuels. Mais je ne pense pas que formaliser un abc pour cela aurait une valeur pratique, que ce soit en codage ou en indication de type statique.

@seberg C'est un excellent synopsis.

Ce problème semble concerner l'utilisation de ndarray dans des contextes qui attendent Sequence ou Iterable ou Container . Une approche simple serait d'avoir des membres sur ndarray qui exposent des vues bon marché qui promettent et fournissent l'interface appropriée et répondent aux isinstance chèques. Par exemple:

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.

Au lieu de ndarray promettant d'être tout pour tout le monde, l'utilisateur demande ce dont il a besoin, et si ndarray peut le fournir, il le fait de la manière la moins chère possible. Si ce n'est pas le cas, cela déclenche une exception. Cela simplifie le code utilisateur en déplaçant le ndim chèque que l'utilisateur devrait faire (en particulier lors de l'utilisation d'annotations de type) dans ndarray .

Cette dernière annotation devrait-elle être Sequence et non Iterable ?

@ eric-wieser Ouais! Merci. Quelles sont vos pensées?

Eh bien, as_subarray_sequence est pratiquement list(arr) :)

@ eric-wieser Oui, je pensais que ce serait moins cher de fournir une vue, mais je n'en ai aucune idée.

Eh bien, list(arr) ne produit que des vues len(arr) , que vous finiriez par produire de toute façon si vous répétiez.

Je pense toujours que nous nous concentrons trop sur ce qui peut être fait et pas assez sur les problèmes actuels. En particulier, toutes les méthodes que vous donnez ci-dessus sont très faciles à implémenter si vous savez que vous avez un ndarray-like (je ne suis pas d'accord avec le fait que les tableaux 0-D ne sont pas des conteneurs). Donc, ils ne seraient utiles que s'il y avait un ABC standardisé pour eux, et dans ce cas, il serait également suffisant de définir que l'indexation de base est compatible numpy et peut-être inclure la propriété .flat .

Le problème d'origine ( random.sample cessé de fonctionner) semble assez hors de propos en raison du temps écoulé. Oui, c'est légèrement ennuyeux, mais c'est peut-être même pour le mieux, car l'utilisateur peut s'attendre à ce que les sous-tableaux ou les éléments soient choisis.

Je suis sûr que nous ne brisons un code-frappe de canard. Certains problèmes surviennent probablement avec la sérialisation (je n'ai pas d'exemples sous la main). Et beaucoup de ces codes n'auront aucun problème avec l'utilisation de isinstance chèques sur ABC s, mais détestent vérifier spécifiquement np.ndarray . Je ne vois pas comment l'ajout de méthodes à ndarray aiderait à cela, nous aurions besoin d'un nouveau ABC , probablement avec un peu plus que la propriété .ndim et éventuellement enchâssant l'itération de style de séquence imbriquée.

Des méthodes telles que celles ci-dessus peuvent être raisonnables en tant que protocole consommateur pour fonctionner avec n'importe quel tableau, mais est-ce le problème que nous essayons de résoudre :)? Ils ne semblent pas être des choses que les séquences Python typiques voudraient exposer.

@ eric-wieser

Vous avez raison bien sûr, mais vous ne pouvez pas parcourir toute la séquence. Vous pourriez ne choisir que quelques éléments.

@seberg

Je pense toujours que nous nous concentrons trop sur ce qui peut être fait et pas assez sur quels sont les problèmes en ce moment

Je suis d'accord avec toi. Quel genre de problèmes imaginez-vous? J'imagine que lorsque numpy 1.10 sortira avec des types, je souhaiterai parfois utiliser un tableau numpy unidimensionnel comme séquence. Si je veux faire cela actuellement, je dois:

  • vérifier qu'il est unidimensionnel, et
  • appelez cast pour dire à mypy qu'il s'agit en fait d'une séquence.

C'est pourquoi je souhaite proposer une méthode pour le faire automatiquement. Je déteste aussi les grandes interfaces, mais il me semble que ces types de méthodes ou de fonctions nues vont être de plus en plus répandues à mesure que les annotations de type se répandent. Qu'est-ce que tu penses?

(Je ne suis pas d'accord que les tableaux 0-D ne sont pas des conteneurs).

Je n'en ai aucune idée, mais actuellement vous augmentez de __len__ pour ceux-ci, il semble donc qu'ils ne fonctionnent pas comme des conteneurs. Je pense qu'il serait utile pour mypy de signaler une erreur si vous passez un tableau 0-D à une fonction qui accepte un conteneur. Il n'attrapera pas si vous créez des conteneurs de tableaux 0-D.

nous aurions besoin d'un nouvel ABC, probablement avec un peu plus que la propriété .ndim et éventuellement enchâssant l'itération de style de séquence imbriquée.

Je ne voulais pas ajouter cela à ma suggestion, mais je pense que c'est là que vous vous dirigez de toute façon. Je suis un utilisateur avide de la bibliothèque JAX merveilleusement conçue. J'imagine que dans le futur, numpy.ndarray et jax.numpy.ndarray (qui a des sous-classes) hériteront tous les deux de quelque NDArray abstrait. Vous pourriez avoir beaucoup plus que ndim . Idéalement, ce serait au moins NDArray(Generic[T]) , et peut-être que l'événement aura aussi la forme ou le nombre de dimensions. Il pourrait avoir __eq__ renvoyant NDArray[np.bool_] . Vous savez probablement mieux que moi :)

Il y a quelques années, j'ai cherché ce problème afin de suggérer que numpy.array devrait hériter de collections.Sequence , mais maintenant je trouve les arguments (surtout le vôtre !!) dans ce fil très convaincants. Les tableaux Numpy ne sont pas vraiment des séquences, et les chausser semble causer plus de mal que de bien. Pourquoi ne pas simplement les laisser être leur propre truc et forcer les utilisateurs à demander explicitement l'interface qu'ils souhaitent?

Et beaucoup de ces codes n'auront aucun problème avec l'utilisation des vérifications isinstance sur les ABC,

Maintenant que vous mentionnez cela, peut-être que toutes mes méthodes proposées auraient dû renvoyer des vues. De cette façon, ils peuvent répondre correctement aux vérifications d'instances.

Des méthodes telles que celles ci-dessus peuvent être raisonnables en tant que protocole consommateur pour fonctionner avec n'importe quel tableau, mais est-ce le problème que nous essayons de résoudre :)? Ils ne semblent pas être des choses que les séquences Python typiques voudraient exposer.

Je suis tout à fait d’accord que la réponse à cela dépend des problèmes que nous essayons de résoudre. Ayant bu l'aide de kool annotation de type, je suis intéressé à écrire un code numpy succinct qui passe mypy sans encombrer de code avec # type: ignore . Quels problèmes avez-vous en tête?

Eh bien, les indices de type et l'interopérabilité avec d'autres objets de type tableau sont probablement une bonne motivation. Je pourrais suggérer d'ouvrir un nouveau numéro ou un fil de discussion sur la liste de diffusion. Pour le moment, je ne sais pas trop à quoi penser ici, la frappe se forme, alors peut-être que cela finira par clarifier certaines choses.

Cette page vous a été utile?
0 / 5 - 0 notes