Uji apakah variabel adalah daftar atau tupel

234

Dengan python, apa cara terbaik untuk menguji apakah suatu variabel berisi daftar atau tupel? (mis. koleksi)

Apakah isinstance()seburuk yang disarankan di sini? http://www.canonical.org/~kragen/isinstance/

Pembaruan: alasan paling umum saya ingin membedakan daftar dari string adalah ketika saya memiliki beberapa pohon bersarang / struktur data dari daftar daftar string dll. Yang saya jelajahi dengan algoritma rekursif dan saya perlu untuk mengetahui kapan saya telah menekan node "leaf".

interstar
sumber
72
Secara luas menolak pengecekan tipe sebagai kejahatan sedikit mudah. Itu bagian dari bahasa. Jika sangat jahat, seseorang harus menulis PEP untuk menghapusnya.
Adam Crossland
4
@Adam Crossland: "Itu bagian dari bahasa." Persis seperti pembagian dengan nol. Itu bisa dihindari. Dalam hal ini, tanpa informasi tambahan, itu mungkin sama sekali tidak perlu. Kebanyakan jenis pemeriksaan dengan Python tidak perlu. Karena tidak semua tidak perlu, beberapa jenis pemeriksaan perlu ada. Tetapi itu tidak berarti itu membantu, berharga, atau bahkan ide yang bagus.
S.Lott
11
Jadi Anda mengatakan bahwa beberapa jenis pemeriksaan diperlukan, tetapi meskipun demikian, itu tidak berguna, tidak berharga, dan ide yang buruk. Maaf, itu tidak masuk akal.
Glenn Maynard
18
"XXX itu jahat" adalah singkatan yang disalahpahami, menyesatkan untuk "cara Anda meminta untuk melakukan XXX menyarankan Anda tidak mengerti kapan itu seharusnya digunakan, dan Anda hampir pasti menginginkan sesuatu yang lain". Itu kemungkinan besar terjadi di sini.
Glenn Maynard
2
Saya tidak menganggapnya sebagai kejahatan. Saya menulis esai singkat tentang kapan itu jahat dan kapan itu bisa dibenarkan. Esai itu mungkin banyak hal - benar, salah, jelas, tidak jelas, menyenangkan, membosankan - tetapi satu hal yang tidak ada adalah pemecatan luas terhadap teknik tersebut.
Kragen Javier Sitaker

Jawaban:

101

Silakan dan gunakan isinstancejika Anda membutuhkannya. Ini agak jahat, karena tidak termasuk urutan kustom, iterator, dan hal-hal lain yang mungkin benar-benar Anda butuhkan. Namun, terkadang Anda perlu berperilaku berbeda jika seseorang, misalnya, melewatkan sebuah string. Preferensi saya ada untuk secara eksplisit memeriksa stratau unicodeseperti:

import types
isinstance(var, types.StringTypes)

NB Jangan salah types.StringTypeuntuk types.StringTypes. Yang terakhir menggabungkan strdan unicodeobjek.

The typesModul dianggap oleh banyak untuk menjadi usang dalam mendukung hanya memeriksa secara langsung terhadap jenis objek, jadi jika Anda lebih suka tidak menggunakan atas, Anda alternatif dapat memeriksa secara eksplisit terhadap strdan unicode, seperti ini:

isinstance(var, (str, unicode)):

Edit:

Lebih baik lagi adalah:

isinstance(var, basestring)

Akhiri edit

Setelah salah satu dari ini, Anda dapat kembali berperilaku seolah-olah Anda mendapatkan urutan normal, membiarkan non-urutan meningkatkan pengecualian yang sesuai.

Melihat hal yang "jahat" tentang pengecekan tipe bukanlah bahwa Anda mungkin ingin berperilaku berbeda untuk jenis objek tertentu, itu adalah bahwa Anda secara artifisial membatasi fungsi Anda dari melakukan hal yang benar dengan jenis objek yang tidak terduga yang sebaliknya akan melakukan hal yang benar. Jika Anda memiliki fallback terakhir yang tidak dicentang, Anda menghapus batasan ini. Perlu dicatat bahwa pengecekan tipe terlalu banyak adalah bau kode yang menunjukkan bahwa Anda mungkin ingin melakukan beberapa refactoring, tetapi itu tidak berarti Anda harus menghindarinya dari getgo.

jcdyer
sumber
2
Modul types adalah sedikit artefak sejarah. Seperti yang disebutkan di docs.python.org/dev/library/types.html#module-types jika Anda benar-benar harus memeriksa strjenisnya, Anda harus menggunakannya secara langsung, alih-alih menggunakan types.StringTypeyang hanya merupakan alias untuk itu. Tapi saya kira jawaban ini tidak menjawab pertanyaan seperti yang diajukan, karena itu tentang "koleksi". Kecuali Anda menggunakan python yang cukup baru untuk memiliki abcmodul itu bukan sesuatu yang dapat Anda gunakan isinstanceuntuk memeriksa, dan bahkan kemudian saya akan merekomendasikan menghindari pemeriksaan jika memungkinkan.
mzz
1
assert isinstance(u'abc', str) == False. Saya setuju bahwa lebih baik untuk memeriksa jenisnya secara langsung, daripada menggunakan typesmodul, tetapi types.StringTypesmelakukan sesuatu yang strtidak: ia mengembalikan True untuk strdan unicodeobjek. Saya akan mengedit respons saya untuk menawarkan pemeriksaan ganda sebagai alternatif.
jcdyer
1
Saya menyadari bahwa saya tidak menjawab pertanyaan memeriksa koleksi secara langsung, tetapi pertanyaan sebenarnya yang diajukan adalah "Apakah isinstancekejahatan?" Dan saya memberikan contoh balasan yang (1) penggunaannya tidak jahat isinstance, karena mundur berarti tidak merusak ducktyping, dan (2) merupakan solusi yang baik untuk motivasi yang sangat umum dimiliki orang-orang karena ingin memeriksa apakah sesuatu adalah a listatau tuple(yaitu untuk mendamaikan mereka dari string).
jcdyer
Saya setuju, dengan peringatan yang sering berguna untuk tipe kustom untuk berperilaku seperti string juga. Tapi Python OO hanya sejauh ini ...
Kragen Javier Sitaker
Apakah class Foo(str): passmelakukan yang Anda inginkan?
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'
wall-e
sumber
1
Tampaknya tidak berfungsi: ketik ([]) ==> daftar; type ([]) adalah list ===> False
sten
3
Dalam Python 2.7.5: type([]) is listpengembalianTrue
David Geiger
54
type(x) in [list,tuple]lebih pendek.
Alex Holcombe
jika x dan ketik (x) adalah daftar: untuk menghindari ketidakcocokan []
Kenichi Shibata
Saya harus gulir ke bawah begitu banyak. : D
Rithwik
38

Tidak ada yang salah dengan menggunakan isinstanceselama itu tidak berlebihan. Jika suatu variabel hanya berupa daftar / tuple maka dokumentasikan antarmuka dan gunakan saja seperti itu. Kalau tidak, cek itu masuk akal:

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

Jenis pemeriksaan ini memang memiliki beberapa kasus penggunaan yang baik, seperti dengan metode string startswith / endswith standar (meskipun untuk lebih akuratnya ini diimplementasikan dalam C di CPython menggunakan pemeriksaan eksplisit untuk melihat apakah itu tuple - ada lebih dari satu cara untuk menyelesaikan masalah ini, sebagaimana disebutkan dalam artikel yang Anda tautkan).

Pemeriksaan eksplisit seringkali lebih baik daripada mencoba menggunakan objek sebagai wadah dan menangani pengecualian - yang dapat menyebabkan semua jenis masalah dengan kode yang dijalankan sebagian atau tidak perlu.

Scott Griffiths
sumber
15
Ini adalah cara yang bagus untuk memeriksa apakah suatu variabel dapat diubah. Namun, itu mungkin tidak akan berfungsi untuk keperluan pertanyaan ini. Harap diperhatikan bahwa string juga dapat diubah dan mungkin akan membuat false positive.
Corey O.
Sebuah setobjek juga merupakan iterable, yang berarti bahwa meskipun Anda pasti dapat memunculkan elemen darinya, tetapi itu tidak menjamin urutan tertentu, yang merupakan hal yang sangat berbahaya untuk algoritma tertentu. Dalam kasus ketika pemesanan elemen tidak masalah, sebuah algoritma yang menggunakan potongan ini berpotensi menghasilkan hasil yang berbeda pada proses yang berbeda!
koo
14

Dokumentasikan argumen itu sebagai perlu urutan, dan gunakan sebagai urutan. Jangan periksa tipenya.

Ignacio Vazquez-Abrams
sumber
12

Bagaimana dengan hasattr(a, "__iter__"):?

Ia memberi tahu jika objek yang dikembalikan dapat diulang sebagai generator. Secara default, tupel dan daftar bisa, tetapi bukan tipe string.

pengguna1914881
sumber
Saya menemukan ini sangat berguna.
javadba
8
Juga menghasilkan True untuk string (setidaknya pada Python 3).
SzieberthAdam
2
Ini jawaban yang salah. Karena tipe 'str' memiliki metode ' iter ' juga. @SzieberthAdam benar. Tipe 'set' juga dapat diubah, tetapi tidak dapat dipesan.
PADYMKO
Dikte juga punya __iter__.
thet
Jika Anda melanjutkan, jenis kustom apa pun mungkin __iter__karena suatu alasan ...
Alexander Irbis
10

Pada Python 2.8 type(list) is listkembali false
saya sarankan membandingkan jenis dengan cara yang mengerikan ini:

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

(setidaknya pada sistem saya, menggunakan anaconda pada Mac OS X Yosemite)

Xanderite
sumber
1
Apakah tipe (a) apakah daftar juga bernilai false?
Dmitriy Sintsov
4
Apakah maksud Anda Python 2.7.8? python.org/dev/peps/pep-0404/#official-pronouncement
Carl
Halo, saya ingin tahu: Mengapa Anda menganggap contoh Anda "mengerikan"?
Seth Connell
type(list) is listkembali Falsekarena type(list)ini type, tidak list. type(list()) is listatau dengan contoh daftar lainnya akan kembali True.
Michael Greene
8

Python menggunakan "Bebek mengetik", yaitu jika variabel kwaks seperti bebek, itu harus bebek. Dalam kasus Anda, Anda mungkin ingin iterable, atau Anda ingin mengakses item pada indeks tertentu. Anda hanya harus melakukan ini: yaitu menggunakan objek di dalam for var:atau var[idx]di dalam tryblok, dan jika Anda mendapatkan pengecualian itu bukan bebek ...

Wim
sumber
7
Masalah dengan ini adalah apakah variterasi string akan terjadi dengan hasil yang mungkin tidak terduga.
Brian M. Hunt
Terlepas dari kenyataan yang dinyatakan oleh Brian M. Hunt, itu adalah solusi yang cukup pythonic, dalam hal meminta pengampunan daripada izin.
Géza Török
6
>>> l = []
>>> l.__class__.__name__ in ('list', 'tuple')
True
tetra5
sumber
3

Jika Anda hanya perlu tahu apakah Anda dapat menggunakan foo[123]notasi dengan variabel, Anda dapat memeriksa keberadaan __getitem__atribut (yang disebut panggilan python saat Anda mengakses dengan indeks) denganhasattr(foo, '__getitem__')

Geoff Reedy
sumber
2

Harus menjadi tes yang lebih kompleks jika Anda benar-benar ingin menangani apa saja sebagai argumen fungsi.

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

Meskipun, biasanya itu cukup dengan hanya mengeja bahwa suatu fungsi mengharapkan iterable dan kemudian periksa saja type(a) != type('').

Juga mungkin terjadi bahwa untuk string Anda memiliki jalur pemrosesan yang sederhana atau Anda akan bersikap baik dan melakukan split dll, jadi Anda tidak ingin berteriak pada string dan jika seseorang mengirimi Anda sesuatu yang aneh, biarkan saja ia memiliki pengecualian.

ZXX
sumber
2

Cara mudah lain untuk mengetahui apakah suatu variabel adalah list atau tuple atau umumnya memeriksa tipe variabel adalah:

    def islist(obj):

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

        else : return False
mahdi omidiyan
sumber
1

Pada prinsipnya, saya setuju dengan Ignacio, di atas, tetapi Anda juga dapat menggunakan tipe untuk memeriksa apakah ada tupel atau daftar.

>>> a = (1,)
>>> type(a)
(type 'tuple')
>>> a = [1]
>>> type(a)
(type 'list')
Adam Crossland
sumber