python: jak rozpoznać, czy zmienna jest tablicą czy skalarem


283

Mam funkcję, która przyjmuje argument NBins. Chcę zadzwonić do tej funkcji za pomocą skalara50 lub tablicy [0, 10, 20, 30]. Jak mogę określić w ramach funkcji, jaka jest długość NBins? lub powiedział inaczej, jeśli jest to skalar lub wektor?

Próbowałem tego:

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

Jak widać, nie mogą ubiegać lensię P, ponieważ nie jest tablicą .... Czy istnieje coś takiego jakisarray lub isscalarw Pythonie?

dzięki


3
Próbowałeś już na to przetestować type?
— Sukrit Kalra

Odpowiedzi:


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

Aby obsłużyć dowolny typ sekwencji, zaznacz collections.Sequencezamiast list.

Uwaga : isinstanceobsługuje również krotkę klas, type(x) in (..., ...)należy unikać sprawdzania i nie jest konieczne.

Możesz także chcieć sprawdzić not isinstance(x, (str, unicode))


3
dzięki, nie wyobrażałem sobie odwrócenia, listby uzyskać fałsz dla skalarów ... dzięki
— otmezger

3
Chociaż jest to świetna odpowiedź, collections.Sequencejest to również ABC dla ciągu znaków, więc należy to wziąć pod uwagę. Używam czegoś takiego if type(x) is not str and isinstance(x, collections.Sequence):. To nie jest świetne, ale jest niezawodne.
— bbenne10,

2
@ bbenne10 na pewno, ale unikaj type, a także sprawdź not isinstance(x, (str, unicode))Python 2
— jamylak

Dlaczego powiedziałeś, że „należy unikać wpisywania (x) w (..., ...) i jest to niepotrzebne”? Jeśli tak mówisz, to byłoby bardzo miłe, aby wyjaśnić, dlaczego, być może nie jestem jedynym, który zastanawia się, dlaczego należy tego unikać.
— Olivier Pons


119

Poprzednie odpowiedzi zakładają, że tablica jest standardową listą Pythona. Jako ktoś, kto często używa numpy, polecam bardzo pythonowy test:

if hasattr(N, "__len__")

12
ciągi mają __len__atrybut (tak sądzę, technicznie nie jest to typ skalarny)
— xofer

20
if hasattr(N, '__len__') and (not isinstance(N, str))poprawnie uwzględniłoby łańcuchy.
— Thucydides411,

1
Weź również pod uwagę dyktat na Pythonie 3
— Bruno Henrique

44

Łącząc odpowiedzi @jamylak i @ jpaddison3 razem, jeśli chcesz być odporny na tablice numpy jako dane wejściowe i obsługiwać je w taki sam sposób jak listy, powinieneś użyć

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

Jest to odporne na podklasy tablic list, krotek i tablic numpy.

A jeśli chcesz być odporny na wszystkie inne podklasy sekwencji (nie tylko listę i krotkę), użyj

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

Dlaczego warto robić to w ten sposób, isinstancea nie porównywać type(P)z wartością docelową? Oto przykład, w którym tworzymy i badamy zachowanie NewListtrywialnej podklasy listy.

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

Pomimo xi yporównywanie jako równe, obchodzenie się z nimi typespowodowałoby inne zachowanie. Jednakże, ponieważ xjest to przykład podklasy list, stosując isinstance(x,list)daje pożądane zachowanie i traktuje xi yw ten sam sposób.


To odpowiedź najbardziej odpowiada moim potrzebom. Właśnie dodałem zestaw. Ponieważ nie chcę być odporny na dyktanda. isinstance(P, (list, tuple, set, np.ndarray))
— Santiago,

32

Czy istnieje odpowiednik isscalar () w numpy? Tak.

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

6
Byłoby lepiej i przykład: >>> np.isscalar('abcd')zwraca True.
— Syrtis Major

dzięki! jest to znacznie bardziej ogólny przykład niż którykolwiek z powyższych i powinien być preferowany. To także bezpośrednia odpowiedź na pytanie PO.
— Cristóbal Sifón

1
Miły. Chociaż jedną z nich jest to, że isscalar (None) zwraca False. Numpy implementuje to jakoreturn (isinstance(num, generic) or type(num) in ScalarType or isinstance(num, numbers.Number))
— Shital Shah

5
Niestety niestety Ta numpy.isscalar()funkcja cierpi na szereg niemożliwych do pogodzenia wad projektowych i prawdopodobnie będzie przestarzała w przyszłości. Parafrazując oficjalną dokumentację : „W prawie wszystkich przypadkach np.ndim(x) == 0należy użyć zamiast np.isscaler(x), ponieważ pierwsza zwróci również prawdę dla tablic 0d”. numpy.isscalar()Zatem solidną, kompatybilną z przodu alternatywą byłoby trywialne zawijanie numpy.ndim(): np.def is_scalar(obj): return np.ndim(obj) == 0
— Cecil Curry

W rzeczywistości nie należy tego oceniać, ponieważ np.isscalarjest mylące. Oficjalny dokument sugeruje używanie np.array.ndimwszędzie, tzn. np.isscalar(np.array(12))Jest fałszywy, podczas gdy powinien być uważany za skalarny, ponieważ np.array(12).ndimwynosi 0.
— knh190

17

Chociaż podejście @ jamylak jest lepsze, tutaj jest podejście alternatywne

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

2
Byłoby wspaniale, gdyby osoba, która głosowała za odpowiedzią, również podała powód.
— Sukrit Kalra

faktycznie przegłosowałem, ale potem zdałem sobie sprawę, że to nie działa w 2.7: >>> p = [] >>> wpisz (p) na (liście) Traceback (ostatnie połączenie ostatnio): Plik „<stdin>” , wiersz 1, w <module>
— Oleg Gryb

@OlegGryb: Spróbuj type(p) in (list, ).
— Sukrit Kalra

ah, to krotka po prawej stronie, a nie lista, mam ją, dziękuję i działa teraz. Żałuję, nie mogę głosować 2 razy - najlepsze jak dotąd rozwiązanie :)
— Oleg Gryb

3

Inne alternatywne podejście (użycie właściwości nazwy klasy ):

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

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

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

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

Nie musisz niczego importować.


3

Oto najlepsze podejście, jakie znalazłem: Sprawdź istnienie __len__i __getitem__.

Możesz zapytać dlaczego? Przyczyny obejmują:

  1. Popularna metoda isinstance(obj, abc.Sequence)zawodzi w przypadku niektórych obiektów, w tym Tensora PyTorcha, ponieważ nie są one implementowane __contains__.
  2. Niestety w kolekcji Python.abc nie ma nic, co sprawdza tylko __len__i __getitem__które są minimalnymi metodami dla obiektów podobnych do tablicy.
  3. Działa na listach, krotkach, ndarray, Tensor itp.

Więc bez zbędnych ceregieli:

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

Zauważ, że dodałem parametry domyślne, ponieważ przez większość czasu możesz chcieć traktować ciągi jako wartości, a nie tablice. Podobnie w przypadku krotek.


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

Możesz sprawdzić typ danych zmiennej.

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

To da ci umieścić jako typ danych P.

<type 'int'>

Abyś mógł odróżnić, że jest to liczba całkowita lub tablica.


2

Dziwi mnie, że takie podstawowe pytanie nie wydaje się mieć bezpośredniej odpowiedzi w pythonie. Wydaje mi się, że prawie wszystkie proponowane odpowiedzi używają pewnego rodzaju sprawdzania typów, co zwykle nie jest zalecane w pythonie i wydają się ograniczone do konkretnego przypadku (zawodzą przy różnych typach liczbowych lub ogólnych iterowalnych obiektach, które nie są krotkami ani listami).

Dla mnie lepiej działa importowanie numpy i używanie array.size, na przykład:

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

Uwaga:

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

Out[5]: 2

ale:

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

Dziwi mnie również fakt, że żaden z nich nie wydaje się mieć do czynienia z generatorami.
— RhysC,

2

Po prostu użyj sizezamiast 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: nazwa „wielkość” nie jest zdefiniowane
— thang

1
To prawda. Używałem rozmiaru numpy, nie zauważając go. Potrzebujesz: od numpy rozmiaru importu
— Mathieu Villion

2
np.size(5)i np.size([5])oba są == 1, więc to nie rozróżnia poprawnie typu (tj. identyfikuje skalar), co moim zdaniem jest celem.
— Michael

To interesująca uwaga. Oryginalne pytanie odnosi się do isscalar, która jest funkcją Matlaba. W Matlabie absolutnie nie ma różnicy między skalarem a tablicą o rozmiarze 1, może to być wektor lub tablica N-dim. IMHO, to plus dla Matlaba.
— Mathieu Villion

0

preds_test [0] ma kształt (128, 128, 1) Pozwala sprawdzić typ danych za pomocą isinstance () funkcja isinstance przyjmuje 2 argumenty. 1. argument to dane 2. argument to typ danych isinstance (preds_test [0], np.ndarray) daje Output jako True. Oznacza to, że preds_test [0] jest tablicą.


0

Aby odpowiedzieć na pytanie w tytule, bezpośrednim sposobem ustalenia, czy zmienna jest skalarem, jest próba przekształcenia jej w zmiennoprzecinkową. Jeśli tak TypeError, to nie jest.

N = [1, 2, 3]
try:
    float(N)
except TypeError:
    print('it is not a scalar')
else:
    print('it is a scalar')
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.