python: cara mengidentifikasi apakah suatu variabel adalah array atau skalar


283

Saya memiliki fungsi yang mengambil argumen NBins. Saya ingin melakukan panggilan ke fungsi ini dengan skalar 50atau array [0, 10, 20, 30]. Bagaimana saya bisa mengidentifikasi dalam fungsi, berapa panjangnyaNBins ? atau berkata berbeda, apakah itu skalar atau vektor?

Saya mencoba ini:

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

Seperti yang Anda lihat, saya tidak dapat menerapkan lenuntuk P, karena itu bukan array .... Apakah ada sesuatu seperti isarrayatauisscalar di python?

Terima kasih


3
Sudahkah Anda mencoba pengujian untuk itu type?
Sukrit Kalra

Jawaban:


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

Untuk mendukung semua jenis urutan, periksa collections.Sequencebukan list.

Catatan : isinstancejuga mendukung tuple kelas, periksa type(x) in (..., ...)harus dihindari dan tidak perlu.

Anda mungkin juga ingin memeriksanya not isinstance(x, (str, unicode))


3
terima kasih, saya tidak membayangkan membalikkan listkesalahan pada skalar ... terima kasih
otmezger

3
Meskipun ini adalah jawaban yang bagus, collections.Sequenceadalah ABC untuk string juga, sehingga harus diperhitungkan. Saya menggunakan sesuatu seperti if type(x) is not str and isinstance(x, collections.Sequence):. Ini tidak bagus, tetapi dapat diandalkan.
bbenne10

2
@ bbenne10 yakin, tapi hindari type, dan juga periksa not isinstance(x, (str, unicode))Python 2
jamylak

Mengapa Anda mengatakan "centang tipe (x) di (..., ...) harus dihindari dan tidak perlu."? Jika Anda berkata begitu, itu akan sangat baik untuk menjelaskan mengapa, mungkin saya bukan satu-satunya yang bertanya-tanya mengapa itu harus dihindari.
Olivier Pons


118

Jawaban sebelumnya mengasumsikan bahwa array adalah daftar standar python. Sebagai seseorang yang sering menggunakan numpy, saya akan merekomendasikan tes yang sangat pythonic:

if hasattr(N, "__len__")

12
string memiliki __len__atribut (jadi saya kira, secara teknis bukan tipe skalar)
xofer

20
if hasattr(N, '__len__') and (not isinstance(N, str))akan menjelaskan string dengan benar.
Thucydides411

1
Juga menjelaskan dict pada Python 3
Bruno Henrique

44

Menggabungkan jawaban @jamylak dan @ jpaddison3 bersamaan, jika Anda harus kuat terhadap array numpy sebagai input dan menanganinya dengan cara yang sama seperti daftar, Anda harus menggunakan

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

Ini kuat terhadap subclass daftar, array tuple dan numpy.

Dan jika Anda ingin menjadi kuat terhadap semua subclass urutan lainnya juga (bukan hanya daftar dan tuple), gunakan

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

Mengapa Anda melakukan hal-hal seperti ini dengan isinstancedan tidak membandingkan type(P)dengan nilai target? Berikut adalah contoh, di mana kita membuat dan mempelajari perilaku NewList, subkelas daftar sepele.

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

Meskipun xdan ymembandingkan sebagai sama, menangani mereka typeakan menghasilkan perilaku yang berbeda. Namun, karena xadalah sebuah contoh dari subclass dari list, menggunakan isinstance(x,list)memberi perilaku yang diinginkan dan memperlakukan xdan ydengan cara yang sama.


Inilah jawaban yang paling sesuai dengan kebutuhan saya. Saya baru saja menambahkan set, juga. Karena saya tidak ingin menjadi kuat terhadap diktat. isinstance(P, (list, tuple, set, np.ndarray))
Santiago

32

Apakah ada yang setara dengan isscalar () di numpy? Iya.

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

6
Akan lebih baik dan contoh: >>> np.isscalar('abcd')pengembalian True.
Syrtis Major

Terima kasih! ini adalah contoh yang jauh lebih umum daripada yang di atas dan harus lebih disukai. Ini juga jawaban langsung untuk pertanyaan OP.
Cristóbal Sifón

1
Bagus. Meskipun satu gotcha adalah bahwa isscalar (Tidak Ada) mengembalikan False. Numpy mengimplementasikan ini sebagaireturn (isinstance(num, generic) or type(num) in ScalarType or isinstance(num, numbers.Number))
Shital Shah

5
Tidak, sayangnya. The numpy.isscalar()Fungsi menderita sejumlah cacat desain dapat didamaikan dan akan mungkin akan usang di beberapa revisi mendatang. Mengutip dokumentasi resmi : "Dalam hampir semua kasus np.ndim(x) == 0harus digunakan, bukan np.isscaler(x), karena yang pertama juga akan benar dengan benar untuk array 0d." Alternatif yang kompatibel dengan maju yang kuat numpy.isscalar()adalah dengan membungkus secara sepele numpy.ndim(): misalnya,def is_scalar(obj): return np.ndim(obj) == 0
Cecil Curry

Sebenarnya ini tidak boleh dibatalkan karena np.isscalarmembingungkan. Doc resmi disarankan menggunakan di np.array.ndimmana - mana, yaitu np.isscalar(np.array(12))Salah sementara itu harus dianggap sebagai skalar karena np.array(12).ndim0.
knh190

17

Sementara, pendekatan @ jamylak adalah yang lebih baik, berikut adalah pendekatan alternatif

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

2
Akan lebih bagus jika orang yang menurunkan jawaban akan memberikan alasan juga.
Sukrit Kalra

Saya benar-benar telah di-upgrade, tetapi kemudian menyadari bahwa itu tidak berfungsi di 2.7: >>> p = [] >>> ketik (p) di (daftar) Traceback (panggilan terakhir terakhir): File "<stdin>" , baris 1, dalam <module>
Oleg Gryb

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

ah, itu tuple di sebelah kanan, bukan daftar, mengerti, terima kasih dan berfungsi sekarang. Saya menyesal, saya tidak bisa melakukan upvote 2 kali - solusi terbaik sejauh ini :)
Oleg Gryb

3

Pendekatan alternatif lain (penggunaan properti nama kelas ):

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

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

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

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

Tidak perlu mengimpor apa pun.


3

Berikut adalah pendekatan terbaik yang saya temukan: Periksa keberadaan __len__dan __getitem__.

Anda mungkin bertanya mengapa? Alasannya meliputi:

  1. Metode populer isinstance(obj, abc.Sequence)gagal pada beberapa objek termasuk PyTorch's Tensor karena mereka tidak mengimplementasikan __contains__.
  2. Sayangnya, tidak ada dalam Python collections.abc yang memeriksa hanya __len__dan __getitem__yang saya rasa adalah metode minimal untuk objek seperti array.
  3. Ini bekerja pada daftar, tuple, ndarray, Tensor dll.

Jadi tanpa basa-basi lagi:

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

Perhatikan bahwa saya telah menambahkan parameter default karena sebagian besar waktu Anda mungkin ingin mempertimbangkan string sebagai nilai, bukan array. Demikian pula untuk 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

Anda dapat memeriksa tipe data variabel.

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

Ini akan memberi Anda put sebagai tipe data P.

<type 'int'>

Sehingga Anda dapat membedakan bahwa itu adalah bilangan bulat atau array.


2

Saya terkejut bahwa pertanyaan mendasar seperti itu tampaknya tidak memiliki jawaban langsung dengan python. Tampak bagi saya bahwa hampir semua jawaban yang diajukan menggunakan semacam pengecekan jenis, yang biasanya tidak disarankan dalam python dan mereka tampaknya terbatas pada kasus tertentu (mereka gagal dengan tipe numerik yang berbeda atau objek iterat generik yang tidak tupel atau daftar).

Bagi saya, yang berfungsi lebih baik adalah mengimpor numpy dan menggunakan array.size, misalnya:

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

Perhatikan juga:

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

Out[5]: 2

tapi:

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

Saya juga terkejut bahwa tidak satupun dari mereka yang berurusan dengan generator.
RhysC

2

Cukup gunakan sizesaja 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: nama 'ukuran' tidak didefinisikan
thang

1
Itu benar. Saya menggunakan ukuran numpy tanpa memperhatikannya. Anda perlu: dari ukuran impor numpy
Mathieu Villion

2
np.size(5)dan np.size([5])keduanya == 1, jadi ini tidak benar membedakan tipe (yaitu, mengidentifikasi skalar), yang saya percaya adalah tujuannya.
michael

Ini adalah komentar yang menarik. Pertanyaan asli mengacu pada isscalar, yang merupakan fungsi Matlab. Dalam Matlab, sama sekali tidak ada perbedaan antara skalar dan array ukuran 1, mungkin itu adalah vektor atau array N-dim. IMHO, ini merupakan nilai tambah untuk Matlab.
Mathieu Villion

0

preds_test [0] memiliki bentuk (128.128,1). Mari kita periksa tipe datanya menggunakan isinstance () function isinstance mengambil 2 argumen. Argumen 1 adalah data Argumen ke-2 adalah tipe data isinstance (preds_test [0], np.ndarray) memberikan Output sebagai True. Itu berarti preds_test [0] adalah sebuah array.


0

Untuk menjawab pertanyaan dalam judul, cara langsung untuk mengetahui apakah suatu variabel adalah skalar adalah dengan mencoba mengubahnya menjadi float. Jika Anda mendapatkannya TypeError, itu tidak benar.

N = [1, 2, 3]
try:
    float(N)
except TypeError:
    print('it is not a scalar')
else:
    print('it is a scalar')
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.