Python: So identifizieren Sie, ob eine Variable ein Array oder ein Skalar ist


283

Ich habe eine Funktion, die das Argument übernimmt NBins. Ich möchte diese Funktion mit einem Skalar 50oder einem Array aufrufen [0, 10, 20, 30]. Wie kann ich innerhalb der Funktion identifizieren, wie lang sie NBinsist? oder anders gesagt, wenn es ein Skalar oder ein Vektor ist?

Ich habe es versucht:

>>> 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()
>>> 

Wie Sie sehen, kann ich nicht anwenden lenzu P, da es kein Array ist .... Gibt es so etwas wie isarrayoder isscalarin Python?

Vielen Dank


3
Haben Sie versucht, es zu testen type?
Sukrit Kalra

Antworten:


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

Um jede Art von Sequenz zu unterstützen, aktivieren Sie collections.Sequenceanstelle von list.

Hinweis : isinstanceUnterstützt auch ein Tupel von Klassen, Überprüfung type(x) in (..., ...)sollte vermieden werden und ist nicht erforderlich .

Sie können auch überprüfen not isinstance(x, (str, unicode))


3
danke, ich habe mir nicht vorgestellt, umzukehren list, um für Skalare falsch zu werden ... danke
otmezger

3
Dies ist zwar eine gute Antwort, collections.Sequenceaber auch ein ABC für Zeichenfolge, so dass dies berücksichtigt werden sollte. Ich benutze so etwas wie if type(x) is not str and isinstance(x, collections.Sequence):. Das ist nicht großartig, aber zuverlässig.
Bbenne10

2
@ bbenne10 sicher, aber vermeiden type, und überprüfen Sie auch not isinstance(x, (str, unicode))auf Python 2
Jamylak

Warum haben Sie gesagt "Check type (x) in (..., ...) sollte vermieden werden und ist unnötig."? Wenn Sie das sagen, wäre das sehr freundlich zu erklären, warum, vielleicht bin ich nicht der einzige, der sich fragt, warum es vermieden werden sollte.
Olivier Pons


118

Bei früheren Antworten wird davon ausgegangen, dass das Array eine Python-Standardliste ist. Als jemand, der häufig Numpy verwendet, würde ich einen sehr pythonischen Test empfehlen von:

if hasattr(N, "__len__")

12
Strings haben ein __len__Attribut (also denke ich, technisch gesehen kein
Skalartyp

20
if hasattr(N, '__len__') and (not isinstance(N, str))würde richtig für Strings erklären.
Thukydides411

1
Berücksichtigen Sie auch das Diktat auf Python 3
Bruno Henrique am

44

Wenn Sie die Antworten von @jamylak und @ jpaddison3 miteinander kombinieren, sollten Sie verwenden, wenn Sie gegenüber numpy-Arrays als Eingabe robust sein und diese wie Listen behandeln möchten

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

Dies ist robust gegenüber Unterklassen von Listen-, Tupel- und Numpy-Arrays.

Und wenn Sie auch gegenüber allen anderen Sequenzunterklassen (nicht nur Liste und Tupel) robust sein möchten, verwenden Sie

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

Warum sollten Sie die Dinge so machen isinstanceund nicht type(P)mit einem Zielwert vergleichen ? Hier ist ein Beispiel, in dem wir das Verhalten NewListeiner trivialen Unterklasse von Listen erstellen und untersuchen .

>>> 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

Trotz xund yVergleich als gleich typewürde der Umgang mit ihnen zu unterschiedlichem Verhalten führen. Da jedoch xeine Instanz einer Unterklasse list, mit isinstance(x,list)dem gewünschten Verhalten und behandelt ergibt xund yauf die gleiche Weise.


Dies ist die Antwort, die meinen Bedürfnissen am besten entspricht. Ich habe gerade auch set hinzugefügt. Weil ich nicht robust gegen Diktate sein will. isinstance(P, (list, tuple, set, np.ndarray))
Santiago

32

Gibt es ein Äquivalent zu isscalar () in numpy? Ja.

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

6
Es wäre besser und ein Beispiel: >>> np.isscalar('abcd')kehrt zurück True.
Syrtis Major

Vielen Dank! Dies ist ein viel allgemeineres Beispiel als eines der oben genannten und sollte bevorzugt werden. Es ist auch eine direkte Antwort auf die Frage des OP.
Cristóbal Sifón

1
Nett. Obwohl ein Problem darin besteht, dass isscalar (None) False zurückgibt. Numpy implementiert dies alsreturn (isinstance(num, generic) or type(num) in ScalarType or isinstance(num, numbers.Number))
Shital Shah

5
Nein, leider. Die numpy.isscalar()Funktion weist eine Reihe unüberbrückbarer Konstruktionsfehler auf und wird wahrscheinlich bei einer zukünftigen Überarbeitung veraltet sein. Um die offizielle Dokumentation zu paraphrasieren : "In fast allen Fällen np.ndim(x) == 0sollte stattdessen verwendet werden np.isscaler(x), da erstere auch für 0d-Arrays korrekt true zurückgeben." Eine robuste vorwärtskompatible Alternative zu numpy.isscalar()wäre daher, trivial zu verpacken numpy.ndim(): zBdef is_scalar(obj): return np.ndim(obj) == 0
Cecil Curry

Eigentlich sollte dies nicht positiv bewertet werden, da np.isscalares verwirrend ist. Offizielles Dokument schlug vor, np.array.ndimüberall zu verwenden, dh np.isscalar(np.array(12))ist falsch, während es als skalar betrachtet werden sollte, da np.array(12).ndimes 0 ist.
knh190

17

Während @ jamylaks Ansatz der bessere ist, gibt es hier einen alternativen Ansatz

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

2
Es wäre großartig gewesen, wenn die Person, die die Antwort abgelehnt hat, auch einen Grund angegeben hätte.
Sukrit Kalra

Ich habe tatsächlich upvoted, aber dann festgestellt, dass es in 2.7 nicht funktioniert: >>> p = [] >>> tippe (p) in (Liste) Traceback (letzter Aufruf zuletzt): Datei "<stdin>" , Zeile 1, in <Modul>
Oleg Gryb

@ LegGryb: Versuchen Sie es type(p) in (list, ).
Sukrit Kalra

Ah, es ist ein Tupel auf der rechten Seite, keine Liste, verstanden, danke und es funktioniert jetzt. Ich bedaure, ich kann nicht 2-mal upvoten - die bisher beste Lösung :)
Oleg Gryb

3

Ein weiterer alternativer Ansatz (Verwendung von Klassenname - Eigenschaft):

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

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

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

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

Sie müssen nichts importieren.


3

Hier ist der beste Ansatz, den ich gefunden habe: Überprüfen Sie die Existenz von __len__und __getitem__.

Sie fragen sich vielleicht warum? Die Gründe umfassen:

  1. Die beliebte Methode isinstance(obj, abc.Sequence)schlägt bei einigen Objekten fehl, einschließlich PyTorchs Tensor, da sie nicht implementiert werden __contains__.
  2. Leider gibt es in Pythons collection.abc nichts, wonach nur gesucht wird __len__und __getitem__was meiner Meinung nach minimale Methoden für Array-ähnliche Objekte sind.
  3. Es funktioniert auf Liste, Tupel, Ndarray, Tensor usw.

Also ohne weiteres:

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

Beachten Sie, dass ich Standardparameter hinzugefügt habe, da Sie Zeichenfolgen meistens als Werte und nicht als Arrays betrachten möchten. Ähnliches gilt für Tupel.


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

Sie können den Datentyp der Variablen überprüfen.

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

Es wird Ihnen als Datentyp von P ausgegeben.

<type 'int'>

Damit Sie unterscheiden können, dass es sich um eine Ganzzahl oder ein Array handelt.


2

Ich bin überrascht, dass eine so grundlegende Frage in Python keine unmittelbare Antwort zu haben scheint. Es scheint mir, dass fast alle vorgeschlagenen Antworten eine Art Typprüfung verwenden, die in Python normalerweise nicht empfohlen wird, und sie scheinen auf einen bestimmten Fall beschränkt zu sein (sie schlagen mit verschiedenen numerischen Typen oder generischen iterierbaren Objekten fehl, die keine Tupel oder Listen sind).

Für mich funktioniert es besser, numpy zu importieren und array.size zu verwenden, zum Beispiel:

>>> 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

Beachten Sie auch:

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

Out[5]: 2

aber:

>>> 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

Ich bin auch überrascht, dass sich keiner von ihnen mit Generatoren zu befassen scheint.
RhysC

2

Einfach verwenden sizestatt 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: Name 'Größe' ist nicht definiert
thang

1
Das ist richtig. Ich habe Numpy Size verwendet, ohne es zu merken. Sie benötigen: von numpy Importgröße
Mathieu Villion

2
np.size(5)und np.size([5])sind beide == 1, so dass dies den Typ nicht richtig unterscheidet (dh einen Skalar identifiziert), was meiner Meinung nach das Ziel ist.
Michael

Dies ist eine interessante Bemerkung. Die ursprüngliche Frage bezieht sich auf isscalar, eine Matlab-Funktion. In Matlab gibt es absolut keinen Unterschied zwischen einem Skalar und einem Array der Größe 1, sei es ein Vektor oder ein N-dim-Array. IMHO, das ist ein Plus für Matlab.
Mathieu Villion

0

preds_test [0] hat die Form (128,128,1). Überprüfen Sie den Datentyp mithilfe der Funktion isinstance (). isinstance akzeptiert 2 Argumente. 1. Argument ist Daten 2. Argument ist Datentyp isinstance (preds_test [0], np.ndarray) gibt Output als True aus. Dies bedeutet, dass preds_test [0] ein Array ist.


0

Um die Frage im Titel zu beantworten, können Sie direkt feststellen, ob eine Variable ein Skalar ist, indem Sie versuchen, sie in einen Float zu konvertieren. Wenn Sie bekommen TypeError, ist es nicht.

N = [1, 2, 3]
try:
    float(N)
except TypeError:
    print('it is not a scalar')
else:
    print('it is a scalar')
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.