ทดสอบว่าตัวแปรคือรายการหรือทูเปิล


234

ในไพ ธ อนวิธีที่ดีที่สุดในการทดสอบว่าตัวแปรมีรายการหรือสิ่งอันดับคืออะไร (เช่นชุดสะสม)

คือisinstance()เป็นความชั่วร้ายตามที่แนะนำที่นี่? http://www.canonical.org/~kragen/isinstance/

อัปเดต: สาเหตุที่พบบ่อยที่สุดที่ฉันต้องการแยกรายการจากสตริงคือเมื่อฉันมีต้นไม้ซ้อน / โครงสร้างข้อมูลในรายการของรายการของสตริง ฯลฯ ซึ่งฉันกำลังสำรวจด้วยอัลกอริทึมแบบเรียกซ้ำและฉันต้องการ รู้เมื่อฉันกดปุ่ม "ใบไม้"


72
การยกเลิกการตรวจสอบประเภทโดยทั่วไปว่าสิ่งชั่วร้ายนั้นทำได้ง่าย มันเป็นส่วนหนึ่งของภาษา ถ้ามันชั่วร้ายคนควรเขียน PEP เพื่อลบมัน
Adam Crossland

4
@ Adam Crossland: "มันเป็นส่วนหนึ่งของภาษา" เหมือนหารด้วยศูนย์ มันสามารถหลีกเลี่ยงได้ ในกรณีนี้หากไม่มีข้อมูลเพิ่มเติมก็อาจไม่จำเป็นอย่างสมบูรณ์ การตรวจสอบประเภทส่วนใหญ่ใน Python นั้นไม่จำเป็น เนื่องจากไม่ใช่สิ่งที่จำเป็นทั้งหมดการตรวจสอบบางประเภทจึงจำเป็นต้องมีอยู่ แต่นั่นไม่ได้หมายความว่ามันมีประโยชน์มีคุณค่าหรือเป็นความคิดที่ดี
S.Lott

11
คุณกำลังบอกว่าต้องการการตรวจสอบบางประเภท แต่ถึงอย่างนั้นมันก็ไร้ประโยชน์ไร้ค่าและเป็นความคิดที่ไม่ดี ขออภัยที่ไม่เหมาะสม
Glenn Maynard

18
"XXX is evil" เข้าใจผิดชวเลขที่เข้าใจผิดสำหรับ "วิธีที่คุณขอให้ทำ XXX แนะนำว่าคุณไม่เข้าใจว่าควรใช้งานจริงเมื่อใดและคุณต้องการสิ่งอื่นอย่างแน่นอน" เป็นไปได้มากว่านี่
Glenn Maynard

2
ฉันไม่ได้ปฏิเสธอย่างกว้างขวางว่าเป็นสิ่งชั่วร้าย ฉันเขียนเรียงความสั้น ๆ เกี่ยวกับเวลาที่มันชั่วและเมื่อสมควร เรียงความนั้นอาจมีหลายสิ่ง - ถูก, ผิด, ชัดเจน, คลุมเครือ, สนุกสนาน, น่าเบื่อ - แต่สิ่งหนึ่งที่มันไม่ได้เป็นการเลิกจ้างในวงกว้างของเทคนิค
Kragen Javier Sitaker

คำตอบ:


101

ไปข้างหน้าและใช้isinstanceถ้าคุณต้องการ มันค่อนข้างชั่วร้ายเนื่องจากไม่รวมลำดับที่กำหนดเองตัววนซ้ำและสิ่งอื่น ๆ ที่คุณอาจต้องการ อย่างไรก็ตามบางครั้งคุณต้องประพฤติตัวแตกต่างกันหากมีคนส่งสตริง การตั้งค่าของฉันจะมีการตรวจสอบอย่างชัดเจนstrหรือunicodeชอบ:

import types
isinstance(var, types.StringTypes)

NB ไม่ผิดสำหรับtypes.StringType types.StringTypesหลังรวมstrและunicodeวัตถุ

typesโมดูลจะพิจารณาโดยมากจะเป็นล้าสมัยในความโปรดปรานของเพียงแค่การตรวจสอบโดยตรงกับประเภทของวัตถุดังนั้นหากคุณไม่ต้องการใช้ข้างต้นคุณสามารถเลือกตรวจสอบอย่างชัดเจนกับstrและunicodeเช่นนี้

isinstance(var, (str, unicode)):

แก้ไข:

ยังดีกว่า:

isinstance(var, basestring)

สิ้นสุดการแก้ไข

หลังจากสิ่งเหล่านี้อย่างใดอย่างหนึ่งคุณสามารถถอยกลับไปทำตัวราวกับว่าคุณได้รับลำดับปกติโดยการให้ลำดับที่ไม่ใช่ข้อผิดพลาดนั้นทำให้เกิดข้อยกเว้นที่เหมาะสม

ดูสิ่งที่ "ชั่วร้าย" เกี่ยวกับการตรวจสอบชนิดไม่ใช่ว่าคุณอาจต้องการทำงานแตกต่างกันสำหรับวัตถุบางชนิดมันเป็นสิ่งที่คุณ จำกัด การทำงานของคุณจากการทำสิ่งที่ถูกต้องด้วยวัตถุประเภทที่ไม่คาดคิดที่จะทำสิ่งที่ถูกต้อง หากคุณมีทางเลือกสุดท้ายที่ไม่ได้ตรวจสอบประเภทคุณจะลบข้อ จำกัด นี้ ควรสังเกตว่าการตรวจสอบประเภทมากเกินไปเป็นกลิ่นรหัสที่บ่งชี้ว่าคุณอาจต้องการทำการปรับโครงสร้างบางอย่าง แต่นั่นไม่ได้หมายความว่าคุณควรหลีกเลี่ยงจากการถูกดักฟัง


2
โมดูลประเภทเป็นบิตของสิ่งประดิษฐ์ทางประวัติศาสตร์ ตามที่ระบุไว้ในdocs.python.org/dev/library/types.html#module-typesหากคุณต้องตรวจสอบstrประเภทที่คุณควรใช้โดยตรงแทนการใช้types.StringTypeซึ่งเป็นเพียงนามแฝง แต่ฉันไม่คิดว่าคำตอบนี้ตอบคำถามตามที่ถามเพราะนั่นเป็นเรื่องเกี่ยวกับ "คอลเลกชัน" ถ้าคุณไม่ใช้ python ใหม่พอที่จะมีabcโมดูลซึ่งไม่ใช่สิ่งที่คุณสามารถใช้isinstanceตรวจสอบได้และฉันก็ขอแนะนำให้หลีกเลี่ยงการตรวจสอบหากเป็นไปได้
mzz

1
assert isinstance(u'abc', str) == False. ฉันยอมรับว่ามันเป็นการดีกว่าที่จะตรวจสอบกับประเภทโดยตรงแทนที่จะใช้typesโมดูล แต่types.StringTypesทำสิ่งที่strไม่ดี: มันคืนค่า True strและunicodeวัตถุ ฉันจะแก้ไขคำตอบเพื่อเสนอการตรวจสอบซ้ำเป็นทางเลือก
jcdyer

1
ฉันรู้ว่าฉันไม่ได้ตอบคำถามในการตรวจสอบคอลเลกชันโดยตรง แต่คำถามจริงที่ถามคือ "มันisinstanceชั่วร้ายหรือไม่" และฉันให้ตัวอย่างที่เคาน์เตอร์ซึ่ง (1) เป็นการใช้ที่ไม่ชั่วisinstanceเพราะมีทางเลือกหมายความว่ามันจะไม่แยกเป็ดและ (2) เป็นทางออกที่ดีสำหรับแรงจูงใจทั่วไปที่ผู้คนต้องการตรวจสอบว่า บางสิ่งบางอย่างเป็นlistหรือtuple(คือการทำให้เข้าใจผิดพวกเขาจากสตริง)
jcdyer

ฉันเห็นด้วยกับข้อแม้ที่มักจะเป็นประโยชน์สำหรับประเภทที่กำหนดเองเพื่อทำตัวเหมือนสตริงเช่นกัน แต่ OO ของ Python ไปไกลเหลือเกิน ...
Kragen Javier Sitaker

ไม่class Foo(str): passทำในสิ่งที่คุณต้องการ?
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
ดูเหมือนจะใช้งานไม่ได้: type ([]) ==> list; ประเภท ([]) คือรายการ ===> เท็จ
เตน

3
ใน Python 2.7.5: type([]) is listส่งคืนTrue
David Geiger

54
type(x) in [list,tuple]สั้นกว่า
อเล็กซ์ Holcombe

ถ้า x และประเภท (x) คือรายการ: เพื่อหลีกเลี่ยงการ [] ไม่ตรงกัน
Kenichi Shibata

ฉันต้องเลื่อนลงมาก : D
Rithwik

38

ไม่มีอะไรผิดปกติกับการใช้isinstanceงานตราบใดที่ไม่ซ้ำซ้อน หากตัวแปรควรเป็น list / tuple ให้ทำเอกสารอินเตอร์เฟสและใช้เป็นเช่นนั้น มิฉะนั้นการตรวจสอบนั้นสมเหตุสมผลอย่างสมบูรณ์แบบ:

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

การตรวจสอบประเภทนี้มีข้อดีในการใช้งานบางอย่างเช่นด้วยวิธีมาตรฐานสตริงstartswith / endswith (แม้ว่าจะถูกต้องสิ่งเหล่านี้จะถูกนำไปใช้ใน C ใน CPython โดยใช้การตรวจสอบที่ชัดเจนเพื่อดูว่าเป็น tuple หรือไม่ เพื่อแก้ไขปัญหานี้ตามที่กล่าวไว้ในบทความที่คุณลิงก์ไป)

การตรวจสอบที่ชัดเจนมักจะดีกว่าการพยายามใช้วัตถุเป็นที่เก็บและจัดการข้อยกเว้น - ซึ่งอาจทำให้เกิดปัญหาทุกประเภทที่มีการเรียกใช้รหัสบางส่วนหรือไม่จำเป็น


15
นี่เป็นวิธีที่ดีในการตรวจสอบว่าตัวแปรทำซ้ำได้หรือไม่ อย่างไรก็ตามอาจไม่สามารถใช้งานได้ตามวัตถุประสงค์ของคำถามนี้ โปรดทราบว่าสตริงสามารถทำซ้ำได้เช่นกันและอาจสร้างผลบวกเป็นเท็จ
Corey O.

setวัตถุยังเป็น iterable ซึ่งหมายความว่าในขณะที่คุณก็สามารถปรากฏองค์ประกอบจากมัน แต่มันไม่ได้รับประกันคำสั่งบางอย่างซึ่งเป็นสิ่งที่อันตรายมากสำหรับขั้นตอนวิธีการบางอย่าง ในกรณีที่การเรียงลำดับองค์ประกอบมีความสำคัญอัลกอริทึมที่ใช้ข้อมูลโค้ดนี้อาจสร้างผลลัพธ์ที่แตกต่างกันในการทำงานที่แตกต่างกัน!
คู

14

จัดทำเอกสารโต้แย้งว่าจำเป็นต้องมีลำดับและใช้เป็นลำดับ อย่าตรวจสอบประเภท


12

วิธีการเกี่ยวกับ: hasattr(a, "__iter__")?

มันบอกว่าวัตถุกลับมาสามารถทำซ้ำมากกว่าเป็นเครื่องกำเนิดไฟฟ้า โดยค่าเริ่มต้นสิ่งอันดับและรายการสามารถทำได้ แต่ไม่ใช่ชนิดสตริง


ฉันพบว่ามันมีประโยชน์จริงๆ
javadba

8
ผลลัพธ์เป็น True สำหรับสตริงด้วย (อย่างน้อยใน Python 3)
SzieberthAdam

2
นี่เป็นคำตอบที่ผิด ตั้งแต่ type 'str' ก็มีเมธอด ' iter ' ด้วยเช่นกัน @SzieberthAdam ถูกต้อง ประเภท 'ชุด' ยังสามารถทำซ้ำได้ แต่ไม่สามารถสั่งซื้อได้
PADYMKO

__iter__นอกจากนี้ยังมี dicts
thet

หากคุณดำเนินการต่อประเภทที่กำหนดเองอาจมี__iter__เหตุผลบางอย่าง ...
Alexander Irbis

10

ใน Python 2.8 ให้type(list) is listผลตอบแทนfalse
ฉันขอแนะนำให้เปรียบเทียบประเภทด้วยวิธีที่น่ากลัวนี้:

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

(อย่างน้อยก็ในระบบของฉันโดยใช้อนาคอนดาบน Mac OS X Yosemite)


1
รายการ (ก) เป็นประเภทยังประเมินว่าเป็นเท็จหรือไม่
Dmitriy Sintsov

4
คุณหมายถึง Python 2.7.8 หรือเปล่า python.org/dev/peps/pep-0404/#official-pronouncement
Carl

สวัสดีฉันอยากรู้: ทำไมคุณถึงพิจารณาตัวอย่างของคุณ "น่ากลัว"
เซทคอนเนล

type(list) is listผลตอบแทนFalseเพราะtype(list)เป็นไม่ได้ type หรือกับคนอื่น ๆเช่นของรายการจะกลับมา listtype(list()) is listTrue
Michael Greene

8

Python ใช้ "การพิมพ์เป็ด" เช่นหากตัวแปร kwaks เหมือนเป็ดมันจะต้องเป็นเป็ด ในกรณีของคุณคุณอาจต้องการให้ทำซ้ำได้หรือคุณต้องการเข้าถึงรายการที่ดัชนีบางอย่าง คุณควรทำสิ่งนี้เช่นใช้วัตถุในfor var:หรือvar[idx]ภายในtryบล็อกและถ้าคุณได้รับการยกเว้นมันไม่ใช่เป็ด ...


7
ปัญหานี้คือถ้าvarเป็นซ้ำสตริงจะเกิดขึ้นกับผลลัพธ์ที่ไม่คาดคิดอาจ
Brian M. Hunt

แม้จะมีความจริงที่ระบุไว้โดย Brian M. Hunt แต่เขาก็เป็นวิธีแก้ปัญหาแบบ pythonic ในแง่ของการขอการให้อภัยมากกว่าการขออนุญาต
GézaTörök


3

หากคุณเพียงแค่ต้องรู้ว่าคุณสามารถใช้foo[123]สัญกรณ์กับตัวแปรคุณสามารถตรวจสอบการมีอยู่ของ__getitem__คุณลักษณะ (ซึ่งเป็นสิ่งที่หลามเรียกเมื่อคุณเข้าถึงโดยดัชนี)hasattr(foo, '__getitem__')


2

จะต้องมีการทดสอบที่ซับซ้อนมากขึ้นถ้าคุณต้องการที่จะจัดการกับอะไรก็ได้เป็นอาร์กิวเมนต์ของฟังก์ชัน

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

แม้ว่ามักจะเพียงพอที่จะเพียงแค่สะกดออกว่าฟังก์ชั่นคาดว่า iterable type(a) != type('')แล้วตรวจสอบเท่านั้น

นอกจากนี้ยังอาจเกิดขึ้นได้ว่าสำหรับสตริงที่คุณมีเส้นทางการประมวลผลที่เรียบง่ายหรือคุณกำลังจะดีและทำแยก ฯลฯ ดังนั้นคุณไม่ต้องการตะโกนใส่สายและถ้ามีคนส่งอะไรแปลก ๆ ให้เขา ข้อยกเว้น.


2

อีกวิธีที่ง่ายในการค้นหาว่าตัวแปรเป็นรายการหรือทูเปิลหรือโดยทั่วไปตรวจสอบชนิดของตัวแปรจะเป็น:

    def islist(obj):

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

        else : return False

1

โดยหลักการแล้วฉันเห็นด้วยกับอิกนาชิโอด้านบน แต่คุณสามารถใช้ประเภทเพื่อตรวจสอบว่ามีบางสิ่งเป็น tuple หรือรายการ

>>> a = (1,)
>>> type(a)
(type 'tuple')
>>> a = [1]
>>> type(a)
(type 'list')
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.