หลาม: วิธีการระบุว่าตัวแปรเป็นอาร์เรย์หรือสเกลาร์


283

NBinsฉันมีฟังก์ชั่นที่ใช้อาร์กิวเมนต์ ฉันต้องการโทรไปยังฟังก์ชั่นนี้ด้วยสเกลาร์50หรืออาเร[0, 10, 20, 30]ย์ ฉันจะระบุได้อย่างไรในฟังก์ชั่นความยาวของNBinsมันคืออะไร? หรือพูดต่างออกไปถ้ามันเป็นเซนต์คิตส์และเนวิส?

ฉันลองสิ่งนี้:

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

อย่างที่คุณเห็นฉันไม่สามารถนำlenไปใช้ได้Pเนื่องจากมันไม่ใช่อาร์เรย์ .... มีอะไรที่คล้ายisarrayหรือisscalarในหลาม?

ขอบคุณ


3
คุณลองทดสอบแล้วtypeหรือยัง
Sukrit Kalra

คำตอบ:


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

การสนับสนุนชนิดของลำดับใด ๆ ตรวจสอบแทนcollections.Sequencelist

หมายเหตุ : isinstanceนอกจากนี้ยังสนับสนุนทูเปิลของคลาสตรวจสอบtype(x) in (..., ...)ควรหลีกเลี่ยงและไม่จำเป็น

คุณอาจต้องการตรวจสอบ not isinstance(x, (str, unicode))


3
ขอบคุณผมไม่ได้จินตนาการ inverting listที่จะได้รับเท็จเกลา ... ขอบคุณ
otmezger

3
ขณะนี้เป็นคำตอบที่ดีcollections.Sequenceคือ ABC สำหรับสายอักขระเช่นกันดังนั้นควรคำนึงถึง if type(x) is not str and isinstance(x, collections.Sequence):ฉันใช้สิ่งที่ต้องการ สิ่งนี้ไม่ดี แต่เชื่อถือได้
bbenne10

2
@ bbenne10 แน่นอน แต่หลีกเลี่ยงtypeและตรวจสอบnot isinstance(x, (str, unicode))Python 2 ด้วย
jamylak

ทำไมคุณถึงพูดว่า "ควรเลือกประเภทการตรวจสอบ (x) ใน (... , ... ) และไม่จำเป็น" ถ้าคุณพูดแบบนั้นมันก็ใจดีมากที่จะอธิบายว่าทำไมบางทีฉันไม่ใช่คนเดียวที่สงสัยว่าทำไมมันควรหลีกเลี่ยง
Olivier Pons


119

คำตอบก่อนหน้านี้สมมติว่าอาร์เรย์เป็นรายการมาตรฐานของหลาม ในฐานะคนที่ใช้งาน numpy บ่อยครั้งฉันขอแนะนำการทดสอบแบบ pythonic ของ:

if hasattr(N, "__len__")

12
สตริงมี__len__คุณลักษณะ (ดังนั้นฉันเดาไม่ใช่เทคนิคสเกลาร์)
xofer

20
if hasattr(N, '__len__') and (not isinstance(N, str))บัญชีจะถูกต้องสำหรับสตริง
Thucydides411

1
รวมทั้งบัญชี dict ใน Python 3
Bruno Henrique

44

การรวมคำตอบของ @jamylak และ @ jpaddison3 เข้าด้วยกันหากคุณจำเป็นต้องมีความทนทานต่ออาร์เรย์ numpy เป็นอินพุตและจัดการในลักษณะเดียวกับรายการคุณควรใช้

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

สิ่งนี้มีความแข็งแกร่งเมื่อเทียบกับ subclasses ของ list, tuple และ numpy arrays

และถ้าคุณต้องการที่จะทนทานต่อ subclasses อื่น ๆ ทั้งหมดของลำดับเช่นกัน (ไม่ใช่แค่ลิสต์และทูเปิล) ให้ใช้

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

ทำไมคุณควรทำสิ่งต่าง ๆ ด้วยวิธีนี้isinstanceและไม่เปรียบเทียบtype(P)กับมูลค่าเป้าหมาย นี่คือตัวอย่างที่เราทำและศึกษาพฤติกรรมของNewListsubclass เล็กน้อยของรายการ

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

แม้จะมีxและyเปรียบเทียบเท่ากันการจัดการพวกเขาโดยtypeจะส่งผลให้พฤติกรรมที่แตกต่าง อย่างไรก็ตามเนื่องจากxเป็นตัวอย่างของคลาสย่อยของการlistใช้isinstance(x,list)ให้พฤติกรรมที่ต้องการและปฏิบัติxและyในลักษณะเดียวกัน


นี่คือคำตอบที่เหมาะสมที่สุดกับความต้องการของฉัน ฉันเพิ่งเพิ่มชุดเช่นกัน เพราะฉันไม่ต้องการที่จะแข็งแกร่งต่อ dicts isinstance(P, (list, tuple, set, np.ndarray))
ซันติอาโก

32

มีเทียบเท่ากับ isscalar () ในจำนวน numpy? ใช่.

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

6
มันจะดีกว่าและตัวอย่าง: ผลตอบแทน>>> np.isscalar('abcd') True
Syrtis Major

ขอบคุณ! นี่เป็นตัวอย่างทั่วไปที่มากกว่าตัวอย่างด้านบนและควรเป็นที่ต้องการ นอกจากนี้ยังเป็นคำตอบสำหรับคำถามของ OP โดยตรง
CristóbalSifón

1
ดี แม้ว่า gotcha หนึ่งอันคือ isscalar (None) จะส่งกลับค่า False Numpy ใช้สิ่งนี้เป็นreturn (isinstance(num, generic) or type(num) in ScalarType or isinstance(num, numbers.Number))
Shital Shah

5
ไม่น่าเศร้า numpy.isscalar()ฟังก์ชั่นได้รับความทุกข์จำนวนของข้อบกพร่องการออกแบบกันไม่ได้และจะอาจจะเลิกใช้ในบางการแก้ไขในอนาคต เมื่อต้องการแปลความหมายเอกสารอย่างเป็นทางการ : "ในเกือบทุกกรณีnp.ndim(x) == 0ควรใช้แทนnp.isscaler(x)เนื่องจากในอดีตจะส่งคืนค่าจริงสำหรับอาร์เรย์ 0d" ทางเลือกที่เข้ากันได้กับฟอร์เวิร์ดที่numpy.isscalar()จะถูกห่อnumpy.ndim()เช่น:def is_scalar(obj): return np.ndim(obj) == 0
Cecil Curry

ที่จริงแล้วสิ่งนี้ไม่ควรถูกอัพทวินเพราะnp.isscalarสับสน เอกสารทางการแนะนำให้ใช้np.array.ndimทุกที่เช่นnp.isscalar(np.array(12))False ในขณะที่ควรพิจารณาว่าเป็น scalar เนื่องจากnp.array(12).ndimเป็น 0
knh190

17

ในขณะที่วิธีการของ @ jamylak นั้นดีกว่านี่คือแนวทางอื่น

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

2
มันคงจะดีถ้าคนที่ downvote คำตอบก็ให้เหตุผลเช่นกัน
Sukrit Kalra

ฉันอัปโหลดแล้ว แต่รู้แล้วว่ามันไม่ทำงานใน 2.7: >>> p = [] >>> type (p) ใน (รายการ) Traceback (การโทรล่าสุดครั้งล่าสุด): ไฟล์ "<stdin>" , บรรทัด 1, ใน <module>
Oleg Gryb

@OlegGryb: type(p) in (list, )ลอง
Sukrit Kalra

อามันเป็นทูเปิลทางด้านขวาไม่ใช่รายการรับมันขอบคุณและใช้งานได้ในขณะนี้ ฉันเสียใจฉันไม่สามารถ upvote 2 ครั้ง - ทางออกที่ดีที่สุดเพื่อให้ห่างไกล :)
Oleg Gryb

3

วิธีการทางเลือกอื่น (การใช้คุณสมบัติชื่อคลาส):

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

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

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

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

ไม่จำเป็นต้องนำเข้าอะไร


3

นี่คือวิธีที่ดีที่สุดที่ฉันได้พบ: ตรวจสอบการดำรงอยู่ของและ__len____getitem__

คุณอาจถามว่าทำไม เหตุผลประกอบด้วย:

  1. วิธีที่นิยมisinstance(obj, abc.Sequence)ล้มเหลวบนวัตถุบางอย่างรวมทั้ง PyTorch ของ Tensor __contains__เพราะพวกเขาไม่ดำเนินการ
  2. น่าเสียดายที่ไม่มีอะไรในคอลเล็กชัน Python ที่ตรวจสอบเฉพาะ__len__และ__getitem__ที่ฉันรู้สึกว่าเป็นวิธีการที่น้อยที่สุดสำหรับวัตถุที่เหมือนอาร์เรย์
  3. มันทำงานในรายการ tuple, ndarray, Tensor ฯลฯ

ดังนั้นโดยไม่ต้องกังวลใจเพิ่มเติม:

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

โปรดทราบว่าฉันได้เพิ่มพารามิเตอร์เริ่มต้นเพราะส่วนใหญ่คุณอาจต้องการพิจารณาสตริงเป็นค่าไม่ใช่อาร์เรย์ ในทำนองเดียวกันสำหรับสิ่งอันดับ



2

คุณสามารถตรวจสอบชนิดข้อมูลของตัวแปร

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

มันจะให้คุณใส่เป็นชนิดข้อมูลของ P

<type 'int'>

เพื่อให้คุณสามารถแยกความแตกต่างว่ามันเป็นจำนวนเต็มหรืออาร์เรย์


2

ฉันประหลาดใจที่คำถามพื้นฐานนั้นดูเหมือนจะไม่มีคำตอบทันทีในไพ ธ อน สำหรับฉันดูเหมือนว่าคำตอบที่เสนอเกือบทั้งหมดใช้การตรวจสอบชนิดบางประเภทซึ่งโดยปกติแล้วจะไม่ได้รับคำแนะนำในภาษาไพ ธ อนและดูเหมือนว่าถูก จำกัด ไว้เฉพาะกรณี (พวกเขาล้มเหลวด้วยประเภทตัวเลขที่แตกต่างกัน

สำหรับฉันสิ่งที่ดีกว่าคือการนำเข้าจำนวนมากและใช้ array.size ตัวอย่างเช่น:

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

หมายเหตุด้วย:

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

Out[5]: 2

แต่:

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

ฉันก็ประหลาดใจเช่นกันว่าไม่มีใครในพวกเขาที่จะจัดการกับเครื่องกำเนิดไฟฟ้า
RhysC

2

เพียงใช้sizeแทน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: ชื่อ 'ขนาด' ไม่ได้ถูกกำหนด
Thang

1
นั่นเป็นเรื่องจริง ฉันใช้ขนาดที่เป็นก้อนโดยไม่สังเกตเห็น คุณต้องการ: จากขนาดการนำเข้าที่มีจำนวนมาก
Mathieu Villion

2
np.size(5)และnp.size([5])ทั้งคู่ == 1ดังนั้นนี่จึงไม่ได้แยกประเภทอย่างถูกต้อง (เช่นระบุสเกลาร์) ซึ่งฉันเชื่อว่าเป็นเป้าหมาย
ไมเคิล

นี่คือคำพูดที่น่าสนใจ คำถามเดิมหมายถึง isscalar ซึ่งเป็นฟังก์ชั่น Matlab ใน Matlab ไม่มีความแตกต่างกันอย่างแน่นอนระหว่างสเกลาร์และอาร์เรย์ขนาด 1 อาจเป็นเวกเตอร์หรืออาร์เรย์ N-dim IMHO นี่เป็นข้อดีสำหรับ Matlab
Mathieu Villion

0

preds_test [0] มีรูปร่าง (128,128,1) ให้ตรวจสอบชนิดข้อมูลโดยใช้ isinstance () ฟังก์ชัน isinstance ใช้ 2 อาร์กิวเมนต์ อาร์กิวเมนต์ที่ 1 คือข้อมูลอาร์กิวเมนต์ที่ 2 คือชนิดข้อมูล isinstance (preds_test [0], np.ndarray) ให้เอาต์พุตเป็น True มันหมายถึง preds_test [0] เป็นอาร์เรย์


0

ในการตอบคำถามในหัวข้อวิธีที่จะบอกได้ว่าตัวแปรคือเซนต์คิตส์และเนวิสคือการพยายามแปลงมันให้ลอย ถ้าคุณได้รับTypeErrorมันไม่ใช่

N = [1, 2, 3]
try:
    float(N)
except TypeError:
    print('it is not a scalar')
else:
    print('it is a scalar')
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.