python: comment identifier si une variable est un tableau ou un scalaire


283

J'ai une fonction qui prend l'argument NBins. Je veux appeler cette fonction avec un scalaire 50ou un tableau [0, 10, 20, 30]. Comment puis-je identifier au sein de la fonction, quelle est sa longueur NBins? ou dit différemment, si c'est un scalaire ou un vecteur?

J'ai essayé ceci:

>>> N=[2,3,5]
>>> P = 5
>>> len(N)
3
>>> len(P)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'int' has no len()
>>> 

Comme vous le voyez, je ne peux pas demander lenà P, car il est pas un tableau .... Y at - il quelque chose comme isarrayou isscalaren python?

Merci


3
Avez-vous essayé de le tester type?
Sukrit Kalra

Réponses:


390
>>> isinstance([0, 10, 20, 30], list)
True
>>> isinstance(50, list)
False

Pour prendre en charge tout type de séquence, cochez collections.Sequenceau lieu de list.

Remarque : isinstanceprend également en charge un tuple de classes, la vérification type(x) in (..., ...)doit être évitée et n'est pas nécessaire.

Vous pouvez également vérifier not isinstance(x, (str, unicode))


3
merci, je n'imaginais pas inverser listpour devenir faux pour les scalaires ... merci
otmezger

3
Bien que ce soit une excellente réponse, collections.Sequencec'est aussi un ABC pour la chaîne, donc cela devrait être pris en compte. J'utilise quelque chose comme if type(x) is not str and isinstance(x, collections.Sequence):. Ce n'est pas génial, mais c'est fiable.
bbenne10

2
@ bbenne10 bien sûr, mais évitez type, et vérifiez également not isinstance(x, (str, unicode))Python 2
jamylak

Pourquoi avez-vous dit que "le type de vérification (x) dans (..., ...) devrait être évité et n'est pas nécessaire."? Si vous le dites, ce serait très aimable d'expliquer pourquoi, je ne suis peut-être pas le seul à me demander pourquoi cela devrait être évité.
Olivier Pons


119

Les réponses précédentes supposent que le tableau est une liste standard python. En tant que personne qui utilise numpy souvent, je recommanderais un test très pythonique de:

if hasattr(N, "__len__")

12
les chaînes ont un __len__attribut (donc je suppose, pas techniquement un type scalaire)
xofer

20
if hasattr(N, '__len__') and (not isinstance(N, str))rendrait correctement compte des chaînes.
Thucydides411

1
Tenez également compte de dict sur Python 3
Bruno Henrique

44

En combinant les réponses de @jamylak et @ jpaddison3 ensemble, si vous devez être robuste contre les tableaux numpy en entrée et les gérer de la même manière que les listes, vous devez utiliser

import numpy as np
isinstance(P, (list, tuple, np.ndarray))

Ceci est robuste contre les sous-classes de tableaux list, tuple et numpy.

Et si vous voulez également être robuste contre toutes les autres sous-classes de séquence (pas seulement la liste et le tuple), utilisez

import collections
import numpy as np
isinstance(P, (collections.Sequence, np.ndarray))

Pourquoi devriez-vous procéder isinstanceainsi sans vous comparer type(P)à une valeur cible? Voici un exemple, où nous créons et étudions le comportement d' NewListune sous-classe triviale de liste.

>>> class NewList(list):
...     isThisAList = '???'
... 
>>> x = NewList([0,1])
>>> y = list([0,1])
>>> print x
[0, 1]
>>> print y
[0, 1]
>>> x==y
True
>>> type(x)
<class '__main__.NewList'>
>>> type(x) is list
False
>>> type(y) is list
True
>>> type(x).__name__
'NewList'
>>> isinstance(x, list)
True

Malgré leur comparaison xet leur yégalité, leur manipulation typeentraînerait un comportement différent. Cependant, puisqu'il xs'agit d'une instance d'une sous-classe de list, using isinstance(x,list)donne le comportement et les traitements souhaités xet yde la même manière.


C'est la réponse qui correspondait le mieux à mes besoins. J'ai juste ajouté un set aussi. Parce que je ne veux pas être robuste contre les dict. isinstance(P, (list, tuple, set, np.ndarray))
Santiago

32

Existe-t-il un équivalent à isscalar () dans numpy? Oui.

>>> np.isscalar(3.1)
True
>>> np.isscalar([3.1])
False
>>> np.isscalar(False)
True

6
Ce serait mieux et un exemple: >>> np.isscalar('abcd')revient True.
Syrtis Major

Merci! il s'agit d'un exemple beaucoup plus général que tout ce qui précède et devrait être préféré. C'est aussi une réponse directe à la question du PO.
Cristóbal Sifón

1
Agréable. Bien que l'un des problèmes est que isscalar (None) renvoie False. Numpy implémente cela commereturn (isinstance(num, generic) or type(num) in ScalarType or isinstance(num, numbers.Number))
Shital Shah

5
Non, malheureusement. La numpy.isscalar()fonction souffre d'un certain nombre de défauts de conception inconciliables et sera probablement déconseillée lors d'une prochaine révision. Pour paraphraser la documentation officielle : "Dans presque tous les cas, np.ndim(x) == 0il faut utiliser à la place de np.isscaler(x), car le premier retournera également correctement true pour les tableaux 0d." Une alternative robuste et compatible avec le futur numpy.isscalar()serait donc de boucler trivialement numpy.ndim(): par exemple,def is_scalar(obj): return np.ndim(obj) == 0
Cecil Curry

En fait, cela ne devrait pas être voté, car np.isscalarc'est déroutant. Doc officiel suggéré d'utiliser np.array.ndimpartout, c'est-à np.isscalar(np.array(12))- dire Faux alors qu'il devrait être considéré comme scalaire car np.array(12).ndimest 0.
knh190

17

Alors que l'approche de @ jamylak est la meilleure, voici une approche alternative

>>> N=[2,3,5]
>>> P = 5
>>> type(P) in (tuple, list)
False
>>> type(N) in (tuple, list)
True

2
Il aurait été formidable que la personne qui a rejeté la réponse donne également une raison.
Sukrit Kalra

j'ai effectivement voté positivement, mais je me suis ensuite rendu compte que cela ne fonctionnait pas en 2.7: >>> p = [] >>> tapez (p) dans (liste) Traceback (dernier appel le plus récent): Fichier "<stdin>" , ligne 1, dans <module>
Oleg Gryb

@OlegGryb: Essayez type(p) in (list, ).
Sukrit Kalra

ah, c'est un tuple à droite, pas une liste, je l'ai, merci et ça marche maintenant. Je regrette, je ne peux pas voter 2 fois - la meilleure solution jusqu'à présent :)
Oleg Gryb

3

Une autre approche alternative (utilisation de la propriété de nom de classe ):

N = [2,3,5]
P = 5

type(N).__name__ == 'list'
True

type(P).__name__ == 'int'
True

type(N).__name__ in ('list', 'tuple')
True

Pas besoin d'importer quoi que ce soit.


3

Voici la meilleure approche que j'ai trouvée: Vérifier l'existence de __len__et__getitem__ .

Vous vous demandez peut-être pourquoi? Les raisons incluent:

  1. La méthode populaire isinstance(obj, abc.Sequence)échoue sur certains objets, y compris le tenseur de PyTorch car ils n'implémentent pas__contains__ .
  2. Malheureusement, rien dans les collections.abc de Python ne vérifie uniquement __len__et__getitem__ qui me semble être des méthodes minimales pour les objets de type tableau.
  3. Il fonctionne sur liste, tuple, ndarray, Tensor etc.

Alors sans plus tarder:

def is_array_like(obj, string_is_array=False, tuple_is_array=True):
    result = hasattr(obj, "__len__") and hasattr(obj, '__getitem__') 
    if result and not string_is_array and isinstance(obj, (str, abc.ByteString)):
        result = False
    if result and not tuple_is_array and isinstance(obj, tuple):
        result = False
    return result

Notez que j'ai ajouté des paramètres par défaut, car la plupart du temps, vous souhaiterez peut-être considérer les chaînes comme des valeurs, et non comme des tableaux. De même pour les tuples.


2
>>> N=[2,3,5]
>>> P = 5
>>> type(P)==type(0)
True
>>> type([1,2])==type(N)
True
>>> type(P)==type([1,2])
False

2

Vous pouvez vérifier le type de données de la variable.

N = [2,3,5]
P = 5
type(P)

Il vous donnera un type de données de P.

<type 'int'>

Pour que vous puissiez différencier qu'il s'agit d'un entier ou d'un tableau.


2

Je suis surpris qu'une telle question de base ne semble pas avoir de réponse immédiate en python. Il me semble que presque toutes les réponses proposées utilisent une sorte de vérification de type, ce qui n'est généralement pas conseillé en python et elles semblent limitées à un cas spécifique (elles échouent avec différents types numériques ou objets génériques itérables qui ne sont pas des tuples ou des listes).

Pour moi, ce qui fonctionne mieux, c'est d'importer numpy et d'utiliser array.size, par exemple:

>>> a=1
>>> np.array(a)
Out[1]: array(1)

>>> np.array(a).size
Out[2]: 1

>>> np.array([1,2]).size
Out[3]: 2

>>> np.array('125')
Out[4]: 1

A noter également:

>>> len(np.array([1,2]))

Out[5]: 2

mais:

>>> len(np.array(a))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-40-f5055b93f729> in <module>()
----> 1 len(np.array(a))

TypeError: len() of unsized object

Je suis également surpris qu'aucun d'entre eux ne semble non plus avoir affaire à des générateurs.
RhysC

2

Utilisez simplement sizeau lieu de len!

>>> from numpy import size
>>> N = [2, 3, 5]
>>> size(N)
3
>>> N = array([2, 3, 5])
>>> size(N)
3
>>> P = 5
>>> size(P)
1

2
NameError: le nom 'size' n'est pas défini
merci

1
C'est vrai. J'utilisais la taille numpy sans le remarquer. Vous avez besoin: de la taille d'importation numpy
Mathieu Villion

2
np.size(5)et np.size([5])sont tous les deux == 1, donc cela ne distingue pas correctement le type (c'est-à-dire, identifier un scalaire), ce qui, je crois, est le but.
Michael

Ceci est une remarque intéressante. La question d'origine fait référence à isscalar, qui est une fonction Matlab. Dans Matlab, il n'y a absolument aucune différence entre un scalaire et un tableau de taille 1, que ce soit un vecteur ou un tableau N-dim. À mon humble avis, c'est un plus pour Matlab.
Mathieu Villion

0

preds_test [0] est de forme (128,128,1) Permet de vérifier son type de données en utilisant la fonction isinstance () isinstance prend 2 arguments. Le premier argument correspond aux données Le deuxième argument correspond au type de données isinstance (preds_test [0], np.ndarray) donne la sortie True. Cela signifie que preds_test [0] est un tableau.


0

Pour répondre à la question dans le titre, un moyen direct de savoir si une variable est un scalaire est d'essayer de la convertir en un flottant. Si vous obtenez TypeError, ce n'est pas le cas.

N = [1, 2, 3]
try:
    float(N)
except TypeError:
    print('it is not a scalar')
else:
    print('it is a scalar')
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.