python: bir değişkenin dizi mi yoksa skaler mi olduğu nasıl belirlenir


283

Argümanı alan bir fonksiyonum var NBins. Bir skalar 50veya bir dizi ile bu işleve çağrı yapmak istiyorum [0, 10, 20, 30]. İşlev içinde nasıl tanımlayabilirim, uzunluğu NBinsnedir? ya da farklı bir şekilde söyledi, eğer bir skaler mi yoksa bir vektör mü?

Bunu denedim:

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

Gördüğünüz gibi, ben uygulayamazsınız leniçin Pbir dizi olmadığından, .... gibi orada şey mi isarrayyoksa isscalarPython?

Teşekkürler


3
Bunun için test etmeyi denediniz typemi?
Sukrit Kalra

Yanıtlar:


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

Herhangi bir sekans türünü desteklemek için, collections.Sequenceyerine kontrol edin list.

not : isinstanceayrıca bir grup dersi destekler, kontrol type(x) in (..., ...)edilmemelidir ve gereksizdir.

Ayrıca kontrol etmek isteyebilirsiniz not isinstance(x, (str, unicode))


3
teşekkürler, listskalerlerde yanlışlık yapmak için ters çevirmeyi hayal etmedim ... teşekkürler
otmezger

3
Bu harika bir cevap olsa collections.Sequenceda, dize için de bir ABC'dir, bu yüzden dikkate alınmalıdır. Gibi bir şey kullanıyorum if type(x) is not str and isinstance(x, collections.Sequence):. Bu harika değil, ama güvenilir.
bbenne10

2
@ bbenne10 emin, ama kaçının typeve ayrıca not isinstance(x, (str, unicode))Python 2 üzerinde kontrol
jamylak

Neden "(..., ...) içindeki kontrol (x) tipinden kaçınılmalı ve gereksiz" dediniz? Eğer böyle derseniz, bunun nedenini açıklamak çok nazik olurdu, belki neden kaçınılması gerektiğini merak eden tek kişi ben değilim.
Olivier Pons


119

Önceki cevaplar dizinin standart bir python listesi olduğunu varsayar. Sık sık numpy kullanan biri olarak, çok pitonik bir test tavsiye ederim:

if hasattr(N, "__len__")

12
dizeleri bir __len__niteliğe sahiptir (bu yüzden teknik olarak bir skaler tip değil sanırım)
xofer 17:14

20
if hasattr(N, '__len__') and (not isinstance(N, str))dizeleri düzgün bir şekilde açıklar.
Thucydides411

1
Ayrıca Python 3
Bruno Henrique

44

@Jamylak ve @ jpaddison3'ün cevaplarını bir araya getirerek, giriş olarak sayısal dizilere karşı sağlam olmanız ve bunları listelerle aynı şekilde işlemeniz gerekiyorsa, kullanmalısınız.

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

Bu liste, tuple ve numpy dizilerinin alt sınıflarına karşı dayanıklıdır.

Ve sıralamanın diğer tüm alt sınıflarına karşı da sağlam olmak istiyorsanız (sadece liste ve grup değil),

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

Neden bir şeyleri bir hedef değerle isinstancekarşılaştırıp değil, bu şekilde yapmalısınız type(P)? İşte NewListönemsiz bir liste alt sınıfını yaptığımız ve çalıştığımız bir örnek .

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

Buna rağmen xve yeşit olarak karşılaştırmak, onları ele almak typefarklı davranışlarla sonuçlanır. Bununla birlikte, bir xalt sınıfının bir örneğidir listkullanılarak, isinstance(x,list)istenilen davranışı ve muamele verir xve yaynı şekilde.


İhtiyacım için en uygun cevap bu. Ben de set ekledim. Çünkü zorbalara karşı sağlam olmak istemiyorum. isinstance(P, (list, tuple, set, np.ndarray))
Santiago

32

Numpy cinsinden isscalar () eşdeğeri var mı? Evet.

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

6
Daha iyi ve bir örnek: >>> np.isscalar('abcd')döner True.
Syrtis Major

Teşekkürler! bu, yukarıdakilerden çok daha genel bir örnektir ve tercih edilmelidir. Aynı zamanda OP'nin sorusuna doğrudan bir cevap.
Cristóbal Sifón

1
Güzel. Her ne kadar bir sorun olsa, isscalar (None) False döndürür. Numpy bunu şu şekilde uygularreturn (isinstance(num, generic) or type(num) in ScalarType or isinstance(num, numbers.Number))
Shah

5
Hayır, ne yazık ki. numpy.isscalar()Fonksiyon uzlaşmaz tasarım kusurları bir dizi uğrar ve olacak muhtemelen bazı ileride revizyon sırasında kaldırılacaktır. Resmi belgeleri açıklamak için : "Hemen hemen her durumda np.ndim(x) == 0kullanılmalıdır np.isscaler(x), çünkü eski olanlar da 0d dizileri için doğru şekilde geri dönecektir." Sağlam ileri-uyumlu bir alternatif numpy.isscalar()bu nedenle önemsiz bir şekilde sarmak olacaktır numpy.ndim(): örneğin,def is_scalar(obj): return np.ndim(obj) == 0
Cecil Curry

Aslında bu np.isscalarkarıştırılmamalıdır çünkü kafa karıştırıcı. Resmi doküman np.array.ndimher yerde kullanılmasını önerdi , yani 0 np.isscalar(np.array(12))olduğu için skaler olarak düşünülecek şekilde Yanlış.np.array(12).ndim
knh190

17

@ Jamylak'ın yaklaşımı daha iyi olsa da, alternatif bir yaklaşım

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

2
Cevabı reddeden kişinin de bir sebep vermesi harika olurdu.
Sukrit Kalra

aslında upvoted, ama sonra deos çalışmıyor olduğunu fark etti: >>> p = [] >>> (liste) (p) (geri) izleme (en son çağrı son): Dosya "<stdin>" , satır 1, <modül>
Oleg Gryb

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

ah, sağdaki bir demet, bir liste değil, anladım, teşekkürler ve şimdi çalışıyor. Pişmanım, 2 kez upvote edemiyorum - şimdiye kadarki en iyi çözüm :)
Oleg Gryb

3

Başka bir alternatif yaklaşım (sınıf adı özelliğinin kullanımı):

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

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

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

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

Hiçbir şey ithal etmeye gerek yok.


3

Rezervasyon varlığı: İşte en iyi ben bulduk yaklaşımdır __len__ve __getitem__.

Nedenini sorabilirsiniz? Nedenleri şunları içerir:

  1. Popüler yöntem isinstance(obj, abc.Sequence), uygulanmadığı için PyTorch'un Tensörü de dahil olmak üzere bazı nesnelerde başarısız olur __contains__.
  2. Ne yazık ki, Python's collections.abc sadece kontrol __len__ve __getitem__dizi benzeri nesneler için en az yöntem olduğunu hissediyorum hiçbir şey yoktur .
  3. Liste, tuple, ndarray, Tensor vb.

Yani daha fazla uzatmadan:

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

Çoğu zaman dizeleri diziler olarak değil, değerler olarak değerlendirmek isteyebileceğiniz için varsayılan parametreleri eklediğimi unutmayın. Benzer şekilde tuples için.


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

Değişkenin veri türünü kontrol edebilirsiniz.

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

Veri türü olarak P vermenizi sağlar.

<type 'int'>

Böylece bir tamsayı veya bir dizi olduğunu ayırt edebilirsiniz.


2

Böyle temel bir sorunun python'da hemen bir cevabı olmadığı görülüyor. Bana göre neredeyse tüm önerilen cevaplar bir tür tip kontrol kullanıyor, bu genellikle python'da tavsiye edilmiyor ve belirli bir durumla sınırlı görünüyorlar (farklı sayısal tiplerle veya tuples veya liste olmayan jenerik tekrarlanabilir nesnelerle başarısız oluyorlar).

Benim için daha iyi olan şey numpy'yi içe aktarmak ve array.size kullanmaktır, örneğin:

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

Ayrıca not:

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

Out[5]: 2

fakat:

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

Ayrıca hiçbirinin jeneratörlerle ilgilenmediğine de şaşırdım.
RhysC

2

sizeBunun yerine kullanın 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: adı 'beden' tanımlı değil
numaranı

1
Bu doğru. Fark etmeden numpy boyutunu kullanıyordum. Gerekenler:
Numpy

2
np.size(5)ve np.size([5])her ikisi de == 1, bu yüzden hedef doğru olduğuna inandığım türü (yani, bir skaler tanımlamak) doğru bir şekilde ayırt etmez.
michael

Bu ilginç bir açıklama. Orijinal soru, bir Matlab işlevi olan isscalar'ı belirtir. Matlab'da, bir skaler ve 1 boyutlu bir dizi arasında kesinlikle bir fark yoktur, bu bir vektör veya N-dim dizisi olabilir. IMHO, bu Matlab için bir artı.
Mathieu Villion

0

preds_test [0] şeklindedir (128,128,1) isinstance () işlevini kullanarak veri türünü kontrol edelim isinstance 2 argüman alır. 1. bağımsız değişken veri 2. bağımsız değişken veri türü isinstance (preds_test [0], np.ndarray) çıktısını True olarak verir. Yani preds_test [0] bir dizi.


0

Başlıktaki soruyu cevaplamak için, bir değişkenin skaler olup olmadığını anlamanın doğrudan yolu, onu bir kayan noktaya dönüştürmeye çalışmaktır. Eğer alırsan TypeError, değil.

N = [1, 2, 3]
try:
    float(N)
except TypeError:
    print('it is not a scalar')
else:
    print('it is a scalar')
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.