python: làm thế nào để xác định nếu một biến là một mảng hoặc vô hướng


283

Tôi có một chức năng có đối số NBins. Tôi muốn thực hiện một cuộc gọi đến hàm này bằng vô hướng 50hoặc một mảng [0, 10, 20, 30]. Làm thế nào tôi có thể xác định trong hàm, độ dài của NBinsnó là bao nhiêu? hoặc nói khác đi, nếu nó là vô hướng hay vectơ?

Tôi đã thử điều này:

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

Như bạn thấy đấy, tôi không thể áp dụng lenđể P, vì nó không phải là một mảng .... Có cái gì đó như isarrayhoặc isscalartrong python?

cảm ơn


3
Bạn đã thử kiểm tra nó typechưa?
Sukrit Kalra

Câu trả lời:


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

Để hỗ trợ bất kỳ loại trình tự, kiểm tra collections.Sequencethay vì list.

lưu ý : isinstancecũng hỗ trợ một bộ các lớp, kiểm tra type(x) in (..., ...)nên tránh và không cần thiết.

Bạn cũng có thể muốn kiểm tra not isinstance(x, (str, unicode))


3
cảm ơn, tôi đã không tưởng tượng việc đảo ngược listđể lấy sai cho vô hướng ... cảm ơn
otmezger

3
Mặc dù đây là một câu trả lời tuyệt vời, collections.Sequencecũng là một ABC cho chuỗi, vì vậy điều đó nên được tính đến. Tôi đang sử dụng một cái gì đó như if type(x) is not str and isinstance(x, collections.Sequence):. Điều này không tốt, nhưng nó đáng tin cậy.
bbenne10

2
@ bbenne10 chắc chắn, nhưng tránh type, và cũng kiểm tra not isinstance(x, (str, unicode))Python 2
jamylak

Tại sao bạn lại nói "nên kiểm tra loại (x) trong (..., ...) và không cần thiết."? Nếu bạn nói như vậy, điều đó sẽ rất tử tế để giải thích tại sao, có lẽ tôi không phải là người duy nhất tự hỏi tại sao nên tránh.
Olivier Pons


118

Các câu trả lời trước đây cho rằng mảng là một danh sách chuẩn python. Là một người thường xuyên sử dụng numpy, tôi khuyên bạn nên thử nghiệm pythonic về:

if hasattr(N, "__len__")

12
các chuỗi có một __len__thuộc tính (vì vậy tôi đoán, về mặt kỹ thuật không phải là một loại vô hướng)
xofer

20
if hasattr(N, '__len__') and (not isinstance(N, str))sẽ đúng tài khoản cho chuỗi.
Thucydides411

1
Đồng thời chiếm tài khoản trên Python 3
Bruno Henrique

44

Kết hợp các câu trả lời của @jamylak và @ jpaddison3 với nhau, nếu bạn cần mạnh mẽ chống lại các mảng khó hiểu như đầu vào và xử lý chúng theo cách giống như danh sách, bạn nên sử dụng

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

Điều này là mạnh mẽ chống lại các lớp con của danh sách, tuple và numpy mảng.

Và nếu bạn cũng muốn mạnh mẽ đối với tất cả các lớp con khác của chuỗi (không chỉ liệt kê và tuple), hãy sử dụng

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

Tại sao bạn nên làm mọi thứ theo cách này isinstancevà không so sánh type(P)với giá trị mục tiêu? Dưới đây là một ví dụ, nơi chúng ta thực hiện và nghiên cứu hành vi của NewList, một lớp con tầm thường của danh sách.

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

Mặc dù xyso sánh như nhau, xử lý chúng typesẽ dẫn đến hành vi khác nhau. Tuy nhiên, vì xlà một thể hiện của một lớp con của list, sử dụng isinstance(x,list)cung cấp cho các hành vi mong muốn và xử lý xytheo cách tương tự.


Đây là câu trả lời phù hợp nhất với nhu cầu của tôi. Tôi chỉ cần thêm bộ, quá. Bởi vì tôi không muốn trở nên mạnh mẽ chống lại dicts. isinstance(P, (list, tuple, set, np.ndarray))
Santiago

32

Có tương đương với isscalar () trong numpy không? Đúng.

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

6
Nó sẽ tốt hơn và một ví dụ: >>> np.isscalar('abcd')trả về True.
Syrtis Major

cảm ơn! đây là một ví dụ tổng quát hơn nhiều so với bất kỳ điều nào ở trên và nên được ưu tiên. Đó cũng là câu trả lời trực tiếp cho câu hỏi của OP.
Cristóbal Sifón

1
Đẹp. Mặc dù một gotcha là isscalar (Không có) trả về Sai. Numpy thực hiện điều này nhưreturn (isinstance(num, generic) or type(num) in ScalarType or isinstance(num, numbers.Number))
Shital Shah

5
Đừng buồn bã. Các numpy.isscalar()chức năng chịu một số lỗi thiết kế không thể hòa giải và có thể sẽ không được chấp nhận tại một số sửa đổi trong tương lai. Để diễn giải tài liệu chính thức : "Trong hầu hết các trường hợp np.ndim(x) == 0nên được sử dụng thay vì np.isscaler(x), vì trước đây cũng sẽ trả về đúng cho các mảng 0d." Do đó, một giải pháp thay thế tương thích mạnh mẽ numpy.isscalar()sẽ là một cách tầm thường numpy.ndim(): ví dụ:def is_scalar(obj): return np.ndim(obj) == 0
Cecil Curry

Trên thực tế điều này không nên được nêu lên vì np.isscalarkhó hiểu. Tài liệu chính thức được đề xuất sử dụng np.array.ndimở mọi nơi, tức np.isscalar(np.array(12))là Sai trong khi nó nên được coi là vô hướng vì np.array(12).ndimlà 0.
knh190

17

Trong khi, cách tiếp cận của @ jamylak là cách tốt hơn, đây là một cách tiếp cận khác

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

2
Sẽ thật tuyệt nếu người đánh giá thấp câu trả lời cũng đưa ra một lý do.
Sukrit Kalra

Tôi thực sự đã nâng cấp, nhưng sau đó nhận ra rằng nó không hoạt động trong 2.7: >>> p = [] >>> gõ (p) trong (danh sách) TracBack (cuộc gọi gần đây nhất): Tệp "<stdin>" , dòng 1, trong <mô-đun>
Oleg Gryb

@OlegGryb: Hãy thử type(p) in (list, ).
Sukrit Kalra

ah, đó là một tuple ở bên phải, không phải là một danh sách, có nó, cảm ơn và nó hoạt động ngay bây giờ. Tôi rất tiếc, tôi không thể nâng cấp 2 lần - giải pháp tốt nhất cho đến nay :)
Oleg Gryb

3

Một cách tiếp cận khác (sử dụng thuộc tính tên lớp ):

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

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

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

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

Không cần nhập gì cả.


3

Đây là cách tiếp cận tốt nhất mà tôi đã tìm thấy: Kiểm tra sự tồn tại của __len____getitem__.

Bạn có thể hỏi tại sao? Những lý do bao gồm:

  1. Phương pháp phổ biến isinstance(obj, abc.Sequence) không thành công trên một số đối tượng, bao gồm cả Tenor của PyTorch vì chúng không thực hiện __contains__.
  2. Thật không may, không có gì trong bộ sưu tập của Python.abc chỉ kiểm tra __len____getitem__tôi cảm thấy đó là các phương thức tối thiểu cho các đối tượng giống như mảng.
  3. Nó hoạt động trên danh sách, tuple, ndarray, Tensor, v.v.

Vì vậy, không có thêm ado:

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

Lưu ý rằng tôi đã thêm các tham số mặc định vì hầu hết thời gian bạn có thể muốn coi chuỗi là giá trị, không phải là mảng. Tương tự cho các bộ dữ liệu.


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

Bạn có thể kiểm tra loại dữ liệu của biến.

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

Nó sẽ cung cấp cho bạn đặt dưới dạng kiểu dữ liệu của P.

<type 'int'>

Vì vậy, bạn có thể phân biệt rằng nó là một số nguyên hoặc một mảng.


2

Tôi ngạc nhiên khi một câu hỏi cơ bản như vậy dường như không có câu trả lời ngay lập tức ở trăn. Dường như với tôi, gần như tất cả các câu trả lời được đề xuất đều sử dụng một số loại kiểm tra, thường không được khuyên dùng trong python và chúng dường như bị hạn chế trong một trường hợp cụ thể (chúng thất bại với các loại số khác nhau hoặc các đối tượng lặp chung không phải là tuples hoặc danh sách).

Đối với tôi, những gì hoạt động tốt hơn là nhập numpy và sử dụng Array.size, ví dụ:

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

Cũng lưu ý:

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

Out[5]: 2

nhưng:

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

Tôi cũng ngạc nhiên khi không ai trong số họ dường như đối phó với máy phát điện.
RhysC

2

Đơn giản chỉ cần sử dụng sizethay vì 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
TênError: tên 'kích thước' không được xác định
thang

1
Đúng. Tôi đã sử dụng kích thước numpy mà không nhận thấy nó. Bạn cần: từ kích thước nhập numpy
Mathieu Villion

2
np.size(5)np.size([5])là cả hai == 1, vì vậy điều này không phân biệt chính xác loại (nghĩa là xác định một vô hướng), mà tôi tin là mục tiêu.
michael

Đây là một nhận xét thú vị. Câu hỏi ban đầu đề cập đến isscalar, là một hàm Matlab. Trong Matlab, hoàn toàn không có sự khác biệt giữa một vô hướng và một mảng có kích thước 1, có thể là một vectơ hoặc một mảng N-dim. IMHO, đây là một điểm cộng cho Matlab.
Mathieu Villion

0

pres_test [0] có hình dạng (128,128,1) Cho phép kiểm tra kiểu dữ liệu của nó bằng cách sử dụng hàm isinstance () isinstance mất 2 đối số. Đối số thứ nhất là dữ liệu Đối số thứ hai là kiểu dữ liệu isinstance (pres_test [0], np.ndarray) cho Kết quả là True. Nó có nghĩa là preds_test [0] là một mảng.


0

Để trả lời câu hỏi trong tiêu đề, một cách trực tiếp để biết một biến có phải là vô hướng hay không là cố gắng chuyển đổi nó thành float. Nếu bạn nhận được TypeError, nó không phải là.

N = [1, 2, 3]
try:
    float(N)
except TypeError:
    print('it is not a scalar')
else:
    print('it is a scalar')
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.