Kiểm tra nếu một biến là một danh sách hoặc tuple


234

Trong python, cách tốt nhất để kiểm tra nếu một biến chứa danh sách hoặc bộ dữ liệu là gì? (tức là một bộ sưu tập)

isinstance()xấu xa như đề nghị ở đây?http://www.canonical.org/~kragen/isinstance/

Cập nhật: lý do phổ biến nhất mà tôi muốn phân biệt danh sách với chuỗi là khi tôi có một cấu trúc dữ liệu / cây được lồng sâu vô hạn của danh sách các danh sách các chuỗi, v.v. mà tôi đang khám phá với thuật toán đệ quy và tôi cần để biết khi nào tôi nhấn các nút "lá".


72
Bỏ qua việc kiểm tra kiểu là xấu xa thì hơi khó. Đó là một phần của ngôn ngữ. Nếu nó quá tệ, ai đó nên viết PEP để loại bỏ nó.
Adam Crossland

4
@Adam Crossland: "Đó là một phần của ngôn ngữ." Cũng giống như chia cho số không. Đó là điều có thể tránh được. Trong trường hợp này, nếu không có thêm thông tin, có lẽ nó hoàn toàn không cần thiết. Hầu hết các loại kiểm tra trong Python là không cần thiết. Vì không phải tất cả là không cần thiết, một số loại kiểm tra cần phải có mặt. Nhưng điều đó không có nghĩa là nó hữu ích, có giá trị hoặc thậm chí là một ý tưởng tốt.
S.Lott

11
Vì vậy, bạn đang nói rằng một số loại kiểm tra là cần thiết, nhưng mặc dù vậy, nó vô dụng, vô giá trị và là một ý tưởng tồi. Xin lỗi, điều đó không có ý nghĩa.
Glenn Maynard

18
"XXX là xấu xa" được hình thành một cách tồi tệ, viết tắt sai lầm cho "cách bạn yêu cầu XXX cho thấy bạn không hiểu khi nào nó thực sự nên được sử dụng và bạn gần như chắc chắn muốn một cái gì đó khác". Đó rất có thể là trường hợp ở đây.
Glenn Maynard

2
Tôi đã không rộng rãi coi nó là xấu xa. Tôi đã viết một bài luận ngắn về khi nào nó xấu và khi nào nó hợp lý. Bài tiểu luận đó có thể có nhiều điều - đúng, sai, rõ ràng, mơ hồ, thú vị, nhàm chán - nhưng có một điều không phải là sự bác bỏ rộng rãi về kỹ thuật.
Kragen Javier Sitaker

Câu trả lời:


101

Đi trước và sử dụng isinstancenếu bạn cần nó. Nó là hơi xấu, vì nó loại trừ các trình tự tùy chỉnh, các vòng lặp và những thứ khác mà bạn thực sự có thể cần. Tuy nhiên, đôi khi bạn cần cư xử khác đi nếu ai đó, chẳng hạn, vượt qua một chuỗi. Sở thích của tôi sẽ là kiểm tra rõ ràng strhoặc unicodethích như vậy:

import types
isinstance(var, types.StringTypes)

NB Đừng nhầm lẫn types.StringTypecho types.StringTypes. Sau này kết hợp strunicodecác đối tượng.

Các typesmô-đun được coi bởi nhiều người cho là lỗi thời ủng hộ việc chỉ kiểm tra trực tiếp chống lại kiểu của đối tượng, vì vậy nếu bạn không muốn sử dụng ở trên, bạn có thể lựa chọn kiểm tra một cách rõ ràng chống lại strunicode, như thế này:

isinstance(var, (str, unicode)):

Biên tập:

Vẫn còn tốt hơn là:

isinstance(var, basestring)

Kết thúc chỉnh sửa

Sau một trong hai điều này, bạn có thể quay lại hành xử như thể bạn đang nhận được một chuỗi bình thường, để cho các chuỗi không đưa ra các ngoại lệ thích hợp.

Hãy xem điều "xấu xa" về kiểm tra kiểu không phải là bạn có thể muốn hành xử khác với một loại đối tượng nhất định, mà là bạn hạn chế một cách giả tạo chức năng của bạn khỏi việc làm đúng với các loại đối tượng bất ngờ sẽ làm điều đúng. Nếu bạn có một dự phòng cuối cùng không được kiểm tra loại, bạn loại bỏ hạn chế này. Cần lưu ý rằng kiểm tra kiểu quá nhiều là mùi mã cho biết bạn có thể muốn thực hiện một số phép tái cấu trúc, nhưng điều đó không nhất thiết có nghĩa là bạn nên tránh nó khỏi getgo.


2
Các mô-đun loại là một chút của một tạo tác lịch sử. Như đã đề cập trên docs.python.org/dev/l Library / type.html # model-type nếu bạn thực sự phải kiểm tra strloại bạn chỉ nên sử dụng trực tiếp, thay vì chỉ sử dụng types.StringTypebí danh cho nó. Nhưng tôi không nghĩ câu trả lời này trả lời câu hỏi như đã hỏi, vì đó là về "một bộ sưu tập". Trừ khi bạn đang sử dụng một con trăn đủ mới để có abcmô-đun không phải là thứ bạn có thể sử dụng isinstanceđể kiểm tra, và thậm chí sau đó tôi sẽ khuyên bạn nên tránh kiểm tra nếu có thể.
mzz

1
assert isinstance(u'abc', str) == False. Tôi đồng ý rằng tốt hơn là kiểm tra trực tiếp với loại, thay vì sử dụng typesmô-đun, nhưng types.StringTypesthực hiện một việc strkhông: nó trả về True cho strunicodecác đối tượng. Tôi sẽ chỉnh sửa phản hồi của mình để đưa ra kiểm tra kép thay thế.
jcdyer

1
Tôi nhận ra rằng tôi đã không trả lời câu hỏi kiểm tra các bộ sưu tập trực tiếp, nhưng câu hỏi thực sự được hỏi là "Có phải là isinstancexấu xa?" Và tôi đã đưa ra một ví dụ ngược lại (1) là việc sử dụng không xấu isinstance, bởi vì có một dự phòng có nghĩa là nó không phá vỡ vịt và (2) là một giải pháp tốt cho một động lực rất phổ biến mà mọi người muốn kiểm tra xem một cái gì đó là một listhoặc tuple(tức là để phân tán chúng khỏi chuỗi).
jcdyer

Tôi đồng ý, với lời cảnh báo thường hữu ích cho các loại tùy chỉnh để hành xử giống như chuỗi. Nhưng OO của Python chỉ đi xa đến thế ...
Kragen Javier Sitaker

class Foo(str): passlàm những gì bạn muốn?
jcdyer

567
if type(x) is list:
    print 'a list'
elif type(x) is tuple:
    print 'a tuple'
else:
    print 'neither a tuple or a list'

1
Dường như không hoạt động: gõ ([]) ==> list; loại ([]) là danh sách ===> Sai
sten

3
Trong Python 2.7.5: type([]) is listtrả vềTrue
David Geiger

54
type(x) in [list,tuple]ngắn hơn
Alex Holcombe

nếu x và loại (x) là danh sách: để tránh sự không phù hợp []
Kenichi Shibata

Tôi đã phải cuộn xuống rất nhiều. : D
Rithwik

38

Không có gì sai khi sử dụng isinstancemiễn là nó không dư thừa. Nếu một biến chỉ nên là một danh sách / tuple thì hãy ghi lại giao diện và chỉ sử dụng nó như vậy. Nếu không, kiểm tra là hoàn toàn hợp lý:

if isinstance(a, collections.Iterable):
    # use as a container
else:
    # not a container!

Loại kiểm tra này có một số trường hợp sử dụng tốt, chẳng hạn như với chuỗi bắt đầu / endswith tiêu chuẩn phương thức (mặc dù để chính xác, chúng được triển khai trong C trong CPython bằng cách sử dụng một kiểm tra rõ ràng để xem liệu đó có phải là một cách hay không - có nhiều hơn một cách để giải quyết vấn đề này, như đã đề cập trong bài viết mà bạn liên kết đến).

Kiểm tra rõ ràng thường tốt hơn so với việc cố gắng sử dụng đối tượng làm vùng chứa và xử lý ngoại lệ - điều đó có thể gây ra tất cả các loại vấn đề với mã được chạy một phần hoặc không cần thiết.


15
Đây là một cách hay để kiểm tra xem một biến có thể lặp lại được không. Tuy nhiên, nó có thể sẽ không hoạt động cho mục đích của câu hỏi này. Hãy lưu ý rằng một chuỗi cũng có thể lặp lại và có thể sẽ tạo ra một dương tính giả.
Corey O.

Một setđối tượng cũng là một lần lặp, điều đó có nghĩa là trong khi bạn chắc chắn có thể bật các phần tử từ nó, nhưng nó không đảm bảo một trật tự nhất định, đây là một điều rất nguy hiểm đối với các thuật toán nhất định. Trong các trường hợp khi thứ tự các phần tử có vấn đề, một thuật toán sử dụng đoạn mã này có khả năng tạo ra các kết quả khác nhau trên các lần chạy khác nhau!
koo

14

Tài liệu đối số là cần phải là một chuỗi và sử dụng nó như là một chuỗi. Đừng kiểm tra loại.


12

Thế còn : hasattr(a, "__iter__")?

Nó cho biết nếu đối tượng trả về có thể được lặp đi lặp lại như một trình tạo. Theo mặc định, bộ dữ liệu và danh sách có thể, nhưng không phải là loại chuỗi.


tôi thấy điều này thực sự hữu ích
javadba

8
Cũng có kết quả Đúng cho chuỗi (ít nhất là trên Python 3).
SzieberthAdam

2
Đây là câu trả lời sai. Vì loại 'str' cũng có phương thức ' iter '. @SzieberthAdam đã đúng. Kiểu 'set' cũng có thể lặp lại, nhưng không thể đặt hàng.
PADYMKO

Ngoài ra còn có __iter__ .
thét

Nếu bạn tiếp tục, bất kỳ loại tùy chỉnh nào cũng có thể có __iter__vì một số lý do ...
Alexander Irbis

10

Trên Python 2.8 type(list) is listtrả về, false
tôi sẽ đề nghị so sánh loại theo cách khủng khiếp này:

if type(a) == type([]) :
  print "variable a is a list"

(ít nhất là trên hệ thống của tôi, sử dụng anaconda trên Mac OS X Yosemite)


1
Có phải loại (a) là danh sách cũng đánh giá là sai?
Dmitriy Sintsov


Xin chào, tôi tò mò: Tại sao bạn coi ví dụ của mình là "khủng khiếp"?
Seth Connell

type(list) is listTrả về Falsetype(list)type, không phải list. type(list()) is listhoặc với bất kỳ trường hợp nào khác của danh sách sẽ trở lại True.
Michael Greene

8

Python sử dụng "Duck Duck", tức là nếu một biến kwaks như vịt, thì đó phải là vịt. Trong trường hợp của bạn, bạn có thể muốn nó có thể lặp lại hoặc bạn muốn truy cập mục này ở một chỉ mục nhất định. Bạn chỉ nên làm điều này: tức là sử dụng đối tượng trong for var:hoặc var[idx]bên trong một trykhối và nếu bạn có ngoại lệ thì đó không phải là con vịt ...


7
Vấn đề với điều này là nếu varviệc lặp chuỗi sẽ xảy ra với kết quả có thể bất ngờ.
Brian M. Hunt

Mặc dù thực tế đã được Brian M. Hunt tuyên bố, đây là một giải pháp hoàn hảo, về mặt yêu cầu sự tha thứ thay vì sự cho phép.
Géza Török

6
>>> l = []
>>> l.__class__.__name__ in ('list', 'tuple')
True

3

Nếu bạn chỉ cần biết nếu bạn có thể sử dụng foo[123]ký hiệu với biến, bạn có thể kiểm tra sự tồn tại của một __getitem__thuộc tính (đó là những gì python gọi khi bạn truy cập theo chỉ mục) vớihasattr(foo, '__getitem__')


2

Phải kiểm tra phức tạp hơn nếu bạn thực sự muốn xử lý mọi thứ như đối số hàm.

type(a) != type('') and hasattr(a, "__iter__")

Mặc dù, thông thường chỉ cần đánh vần rằng một hàm mong đợi có thể lặp lại và sau đó chỉ kiểm tra type(a) != type('') .

Ngoài ra, có thể xảy ra rằng đối với một chuỗi bạn có một đường dẫn xử lý đơn giản hoặc bạn sẽ trở nên tốt đẹp và thực hiện phân tách, v.v., vì vậy bạn không muốn hét lên chuỗi và nếu ai đó gửi cho bạn thứ gì đó kỳ lạ, hãy để anh ta có một ngoại lệ.


2

Một cách dễ dàng khác để tìm hiểu xem một biến là danh sách hoặc tuple hoặc thường kiểm tra loại biến sẽ là:

    def islist(obj):

        if ("list" in str(type(obj)) ): return True

        else : return False

1

Về nguyên tắc, tôi đồng ý với Ignacio, ở trên, nhưng bạn cũng có thể sử dụng loại để kiểm tra xem một cái gì đó là một tuple hoặc một danh sách.

>>> a = (1,)
>>> type(a)
(type 'tuple')
>>> a = [1]
>>> type(a)
(type 'list')
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.