วิธีการตรวจสอบว่าวัตถุเป็นรายการหรือ tuple (แต่ไม่ใช่สตริง)?


444

นี่คือสิ่งที่ผมทำตามปกติในการสั่งซื้อเพื่อให้แน่ใจว่าการป้อนข้อมูลที่เป็นlist/ tuple- strแต่ไม่ได้เป็น เพราะหลายครั้งที่ผมเจอข้อบกพร่องที่ฟังก์ชั่นผ่านstrวัตถุโดยไม่ได้ตั้งใจและฟังก์ชั่นเป้าหมายไม่for x in lstสมมติว่าlstเป็นจริงหรือlisttuple

assert isinstance(lst, (list, tuple))

คำถามของฉันคือ: มีวิธีที่ดีกว่าในการบรรลุเป้าหมายนี้หรือไม่?


9
รายการ (lst) คืออะไร
jackalope

1
ไม่ใช่ isinstance (คีย์, six.string_types)
wyx

คำตอบ:


332

ในงูหลาม 2 เท่านั้น (ไม่ใช่งูหลาม 3):

assert not isinstance(lst, basestring)

เป็นจริงสิ่งที่คุณต้องการมิฉะนั้นคุณจะพลาดในสิ่งต่างๆมากมายซึ่งการกระทำเช่นรายการ แต่ไม่ได้เป็นคลาสย่อยหรือlisttuple


91
ใช่นี่คือคำตอบที่ถูกต้อง ในหลาม 3 จะหายไปและคุณเพียงแค่ตรวจสอบbasestring isinstance(lst, str)
steveha

5
มีหลายสิ่งที่คุณสามารถทำซ้ำเช่นรายการเช่นsetนิพจน์ตัวสร้างตัววนซ้ำ มีสิ่งที่แปลกใหม่เช่นmmap, สิ่งแปลกใหม่น้อยลงarrayซึ่งทำหน้าที่เหมือนรายการและอาจจะลืมไปกว่านี้
Nick Craig-Wood

50
มันเป็นมูลค่า noting ที่ว่านี้ไม่ได้รับประกันว่าlstเป็น iterable ขณะที่เดิมได้ (เช่น int จะผ่านการตรวจสอบนี้)
ปีเตอร์กิบสัน

11
@PeterGibson - การรวมกันของทั้งสองจะให้การตรวจสอบที่ถูกต้องและมีข้อ จำกัด มากขึ้นและให้แน่ใจว่า 1) lst เป็น iterable, 2) lst ไม่ใช่สตริง assert isinstance(lst, (list, tuple)) and assert not isinstance(lst, basestring)
strongMA

4
ทีนี้วิธีนี้จะตรวจสอบเฉพาะชนิดที่ได้มาจากสตริง แต่สิ่งที่เกี่ยวกับจำนวนเต็มคู่หรือประเภทอื่น ๆ ที่ไม่สามารถทำซ้ำได้?
Eneko Alonso

171

จำไว้ว่าใน Python เราต้องการใช้ "การพิมพ์เป็ด" ดังนั้นสิ่งใดก็ตามที่ทำหน้าที่เหมือนรายการจึงถือว่าเป็นรายการได้ ดังนั้นอย่าตรวจสอบประเภทของรายการเพียงดูว่ามันทำหน้าที่เหมือนกับรายการหรือไม่

แต่สายอักขระทำหน้าที่เหมือนรายการเช่นกันและบ่อยครั้งนั้นไม่ใช่สิ่งที่เราต้องการ มีบางครั้งที่มันเป็นปัญหา! ดังนั้นตรวจสอบสตริงอย่างชัดเจน แต่จากนั้นใช้การพิมพ์เป็ด

นี่คือฟังก์ชั่นที่ฉันเขียนเพื่อความสนุก มันเป็นรุ่นพิเศษrepr()ที่พิมพ์ลำดับใด ๆ ในวงเล็บมุม ('<', '>')

def srepr(arg):
    if isinstance(arg, basestring): # Python 3: isinstance(arg, str)
        return repr(arg)
    try:
        return '<' + ", ".join(srepr(x) for x in arg) + '>'
    except TypeError: # catch when for loop fails
        return repr(arg) # not a sequence so just return repr

นี่คือสะอาดและสง่างามโดยรวม แต่สิ่งที่isinstance()ตรวจสอบทำที่นั่น? นั่นคือการแฮ็ค แต่มันเป็นสิ่งสำคัญ

ฟังก์ชั่นนี้เรียกตัวเองซ้ำในสิ่งที่ทำหน้าที่เหมือนรายการ หากเราไม่ได้จัดการกับสายอักขระโดยเฉพาะมันจะได้รับการปฏิบัติเหมือนเป็นรายการและแยกอักขระทีละตัว แต่แล้วการโทรซ้ำจะพยายามรักษาตัวละครแต่ละตัวเป็นรายการ - และมันก็ใช้ได้ แม้แต่สตริงตัวละครเดียวก็ใช้เป็นรายการได้! ฟังก์ชั่นจะยังคงเรียกตัวเองซ้ำ ๆ จนกว่าจะล้นสแต็ค

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

หมายเหตุ: try/ exceptเป็นวิธีที่สะอาดที่สุดในการแสดงเจตนาของเรา แต่ถ้ารหัสนี้มีความสำคัญต่อเวลาเราอาจต้องการแทนที่ด้วยการทดสอบบางประเภทเพื่อดูว่าargเป็นลำดับหรือไม่ แทนที่จะทดสอบประเภทเราควรทดสอบพฤติกรรม ถ้ามันมี.strip()เมธอดมันเป็นสตริงดังนั้นอย่าคิดว่ามันเป็นลำดับ มิฉะนั้นหากสามารถทำดัชนีได้หรือทำซ้ำได้ก็เป็นลำดับ:

def is_sequence(arg):
    return (not hasattr(arg, "strip") and
            hasattr(arg, "__getitem__") or
            hasattr(arg, "__iter__"))

def srepr(arg):
    if is_sequence(arg):
        return '<' + ", ".join(srepr(x) for x in arg) + '>'
    return repr(arg)

แก้ไข: เดิมฉันเขียนข้างต้นด้วยการตรวจสอบ__getslice__()แต่ฉันสังเกตเห็นว่าในcollectionsเอกสารประกอบโมดูลวิธีที่น่าสนใจคือ__getitem__(); มันสมเหตุสมผลแล้วนั่นคือวิธีที่คุณจัดทำดัชนีวัตถุ ที่ดูเหมือนพื้นฐานมากกว่า__getslice__()ดังนั้นฉันเปลี่ยนข้างต้น


2
@stantonk ขอบคุณที่พูดอย่างนั้น แต่ฉันคิดว่ามีคำตอบที่ยอมรับแล้วเมื่อฉันเขียนสิ่งนี้และฉันไม่คาดหวังว่าคำตอบที่ยอมรับจะเปลี่ยนไป
steveha

@steveha: sreprเป็นความคิดที่น่าสนใจมาก แต่ฉันถือความคิดเห็นที่แตกต่างจากคุณว่ามันจำเป็นต้องเป็นกรณีพิเศษstrหรือไม่ ใช่strมันเป็นเรื่องที่ชัดเจนและเป็นเรื่องธรรมดาที่จะทำให้เกิดการวนซ้ำแบบไม่รู้sreprจบ แต่ฉันสามารถจินตนาการได้ง่าย ๆ iterables กำหนดโดยผู้ใช้ที่ทำงานในลักษณะเดียวกัน (มีหรือไม่มีเหตุผลที่ดี) แทนที่จะเป็นกรณีพิเศษstrเราควรยอมรับว่าวิธีนี้อาจทำให้เกิดการเรียกซ้ำแบบไม่สิ้นสุดและยอมรับวิธีการจัดการกับมัน ฉันจะโพสต์คำแนะนำของฉันในคำตอบ
สูงสุด

1
ฉันคิดว่านี่เป็นเส้นทางที่ถูกต้องอย่างแน่นอน อย่างไรก็ตามเพื่อจัดการกรณีพิเศษ (ของสายอักขระในสถานการณ์นี้) ฉันคิดว่าเราควรถามคำถามว่า "มนุษย์จะบอกความแตกต่างได้อย่างไร" ตัวอย่างเช่นพิจารณาอาร์กิวเมนต์ฟังก์ชันที่สามารถเป็นรายการที่อยู่อีเมลหรือที่อยู่อีเมลเดียว (โปรดทราบว่าสตริงเป็นเพียงรายการของอักขระ) ให้ตัวแปรนี้กับมนุษย์ จะบอกได้อย่างไรว่ามันคืออะไร? วิธีที่ง่ายที่สุดที่ฉันคิดได้คือดูว่ามีตัวละครกี่ตัวในแต่ละรายการของรายการ ถ้ามันมากกว่า 1 ข้อโต้แย้งจะไม่สามารถเป็นรายชื่อตัวละครได้
Josh

1
ฉันคิดเกี่ยวกับเรื่องนี้เล็กน้อยและพูดคุยกับคนอื่นไม่กี่คนและฉันคิดว่าsrepr()ดีตามที่เป็น เราต้องการฟังก์ชั่นวนซ้ำเพื่อจัดการกับสิ่งต่าง ๆ เช่นรายการที่ซ้อนอยู่ในรายการอื่น แต่สำหรับสายที่เราจะค่อนข้างมีพวกเขาพิมพ์เป็นมากกว่าที่จะเป็น"foo" <'f', 'o', 'o'>ดังนั้นการตรวจสอบสตริงอย่างชัดเจนจึงสมเหตุสมผลดีที่นี่ นอกจากนี้ยังมีจริงๆไม่ตัวอย่างอื่น ๆ ของชนิดข้อมูลที่ iterating เสมอกลับ iterable และเรียกซ้ำมักจะทำให้เกิดการแตกล้นดังนั้นเราจึงไม่จำเป็นต้องมีคุณสมบัติพิเศษในการทดสอบนี้ ( "การปฏิบัติจริงเต้นบริสุทธิ์")
steveha

1
สิ่งนี้ไม่ทำงานใน Python 3 เนื่องจากสตริงมี__iter__()วิธีการใน Python 3 แต่ไม่ได้อยู่ใน Python 2 คุณไม่พบวงเล็บในis_sequence()คุณควรอ่าน:return (not hasattr(arg, "strip") and (hasattr(arg, "__getitem__") or hasattr(arg, "__iter__")))
MiniQuark

124
H = "Hello"

if type(H) is list or type(H) is tuple:
    ## Do Something.
else
    ## Do Something.

11
ยกเว้นว่ามันจะไม่ใช้สำนวน Python ของการพิมพ์เป็ดเพราะผู้วิจารณ์คนอื่น ๆ ได้ชี้ให้เห็น (แม้ว่ามันจะตอบคำถามโดยตรงและหมดจด)
Soren Bjornstad

7
คำตอบนี้ยอมรับได้น้อยกว่าคนอื่น ๆ เพราะมันไม่อนุญาตให้ใช้การพิมพ์เป็ดและมันล้มเหลวในกรณีที่ง่ายของ subclassing (ตัวอย่างทั่วไปคือคลาส namedtuple)
Philippe Gauthier

11
"ไม่อนุญาตให้พิมพ์เป็ด" ไม่ได้ทำให้คำตอบที่ยอมรับได้น้อยลงโดยเฉพาะเมื่อคำตอบนี้ตอบคำถามได้จริง
Petri

4
ฉันตอบคำถามนี้แล้ว แต่if isinstance( H, (list, tuple) ): ...สั้นและชัดเจนกว่า
shahar_m

2
รูปแบบทางเลือก:if type(H) in [list, tuple]:
Štefan Schindler

77

สำหรับ Python 3:

import collections.abc

if isinstance(obj, collections.abc.Sequence) and not isinstance(obj, str):
    print("obj is a sequence (list, tuple, etc) but not a string")

เปลี่ยนเป็นเวอร์ชั่น 3.3: ย้ายคอลเลกชั่นคลาสฐานบทคัดย่อไปยังโมดูล collection.abc สำหรับความเข้ากันได้ย้อนหลังพวกเขาจะยังคงมองเห็นได้ในโมดูลนี้เช่นกันจนกระทั่งรุ่น 3.8 ซึ่งจะหยุดทำงาน

สำหรับ Python 2:

import collections

if isinstance(obj, collections.Sequence) and not isinstance(obj, basestring):
    print "obj is a sequence (list, tuple, etc) but not a string or unicode"

5
ว้าว! มันใช้งานได้ดีมากและรวบรัดกว่าคำตอบที่ถูกต้องอื่น ๆ ฉันไม่มีความคิดว่าประเภทในตัวสืบทอดมาจากcollections.Sequenceแต่ฉันทดสอบมันและฉันเห็นว่าพวกเขาทำ ก็xrangeเช่นกัน ยิ่งไปกว่านี้ไม่รวมการทดสอบdictซึ่งมีทั้งและ__getitem__ __iter__
Neil Mayhew

ความคิดใดว่าทำไมผลของการinspect.getmro(list)ไม่รวมSequenceถึง? เราควรคิดอย่างไรว่าเราจะทำอย่างไรกับisinstanceเมื่อgetmroไม่แสดงทุกอย่าง
Steve Jorgensen

@SteveJorgensen วิธีการแก้ไขคำสั่งกำหนดเส้นทางการค้นหาคลาสที่ใช้โดย Python เพื่อค้นหาวิธีการที่เหมาะสมที่จะใช้ในชั้นเรียน Sequenceเป็นคลาสนามธรรม
suzanshakya

3
ใน Python3 คุณสามารถแทนที่ isinstance (obj, basestring) ด้วย isinstance (obj, str) และที่ควรใช้
Adrian Keister

2
ใน Python 3 คุณต้องการและไม่ใช่ isinstance (obj, bytes) ... หากคุณต้องการรายชื่อของสิ่งต่าง ๆ และไม่เพียงแค่ระบุจำนวนไบต์ ...
Erik Aronesty

35

Python กับรสชาติของ PHP:

def is_array(var):
    return isinstance(var, (list, tuple))

6
Python เป็นภาษาที่พิมพ์ด้วยเป็ดดังนั้นคุณควรตรวจสอบว่า var มีคุณสมบัติ__getitem__หรือไม่ นอกจากนี้ชื่อก็ทำให้เข้าใจผิดเนื่องจากยังมีโมดูลอาร์เรย์ และ var ยังอาจจะเป็น numpy.ndarray หรือชนิดอื่น ๆ __getitem__ซึ่งมี ดูstackoverflow.com/a/1835259/470560สำหรับคำตอบที่ถูกต้อง
peterhil

9
@peterhil strยังมี__getitem__จึงตรวจสอบของคุณไม่ได้ยกเว้นstr
erikbwork

9
ดังนั้นคำสั่ง การตรวจสอบ__getitem__คือคำแนะนำที่ไม่ดีที่นี่
Petri

10

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

ฟังดูเหมือนเป็นคำถามเชิงโวหาร แต่ไม่ใช่ คำตอบของ "ทำไมฉันควรตรวจสอบประเภทของการโต้แย้ง" อาจจะแนะนำวิธีแก้ไขปัญหาจริงไม่ใช่ปัญหาที่รับรู้ ทำไมข้อผิดพลาดเมื่อส่งผ่านสตริงไปยังฟังก์ชัน นอกจากนี้ถ้ามันเป็นข้อผิดพลาดเมื่อสตริงถูกส่งผ่านไปยังฟังก์ชั่นนี้มันก็เป็นข้อผิดพลาดถ้าอื่น ๆ ที่ไม่ใช่รายการ / tuple iterable ถูกส่งผ่านไปยัง ทำไมหรือทำไมไม่?

ผมคิดว่าคำตอบที่พบบ่อยที่สุดคำถามที่มีแนวโน้มที่จะพัฒนาที่ผู้เขียนจะคาดหวังว่าฟังก์ชั่นการทำงานราวกับว่าพวกเขาต้องการเขียนf("abc") f(["abc"])อาจมีสถานการณ์ที่เหมาะสมกว่าในการปกป้องนักพัฒนาซอฟต์แวร์จากตัวเองมากกว่าที่จะรองรับกรณีการใช้งานการวนซ้ำข้ามอักขระในสตริง แต่ฉันจะคิดให้นานและหนักหน่วงก่อน


16
“ แต่ฉันจะคิดให้นานและหนักหนาเสียก่อน” ฉันจะไม่ ถ้าฟังก์ชั่นนั้นควรจะเป็นฟังก์ชั่น list-y ดังนั้นก็ใช่ว่ามันควรจะปฏิบัติต่อพวกมันเหมือนกัน (กล่าวคือเมื่อได้รับรายการให้คายมันออกไปด้านหลังสิ่งต่าง ๆ เช่นนั้น) อย่างไรก็ตามถ้ามันเป็นฟังก์ชั่นที่หนึ่งในอาร์กิวเมนต์สามารถเป็นได้ทั้งสตริงหรือรายการของสตริง (ซึ่งเป็นความต้องการทั่วไป) จากนั้นบังคับให้นักพัฒนาที่ใช้ฟังก์ชั่นนั้นป้อนพารามิเตอร์ภายในอาร์เรย์เสมอ . ลองคิดดูว่าคุณจัดการอย่างไรพูดอินพุต JSON แน่นอนว่าคุณต้องการรักษารายการของวัตถุที่แตกต่างจากสตริง
Jordan Reiter

8

ลองใช้วิธีนี้ในการอ่านและแนวทางปฏิบัติที่ดีที่สุด:

Python2

import types
if isinstance(lst, types.ListType) or isinstance(lst, types.TupleType):
    # Do something

Python3

import typing
if isinstance(lst, typing.List) or isinstance(lst, typing.Tuple):
    # Do something

หวังว่ามันจะช่วย


Python 3.6.5:AttributeError: module 'types' has no attribute 'ListType'
Juha Untinen

1
ใน Python 3 คือ: from typing import List-> isinstance([1, 2, 3], List= Trueและisinstance("asd", List)= False
Juha Untinen

5

strวัตถุไม่ได้มี__iter__แอตทริบิวต์

>>> hasattr('', '__iter__')
False 

เพื่อให้คุณสามารถตรวจสอบ

assert hasattr(x, '__iter__')

และสิ่งนี้จะเพิ่มสิ่งที่ดีAssertionErrorสำหรับวัตถุที่ไม่ทำซ้ำอื่น ๆ ด้วย

แก้ไข: เนื่องจาก Tim กล่าวถึงความคิดเห็นสิ่งนี้จะใช้ได้ใน python 2.x เท่านั้นไม่ใช่ 3.x


8
ระวัง: ใน Python 3 hasattr('','__iter__')จะกลับTrueมา และแน่นอนว่าเหมาะสมเพราะคุณสามารถวนซ้ำสตริงได้
Tim Pietzcker

1
จริงๆ? ฉันไม่รู้ ฉันคิดเสมอว่านี่เป็นวิธีการแก้ปัญหาที่สง่างาม
Moe

1
การทดสอบนี้ไม่สามารถใช้งานได้กับ pyodbc.Row มันไม่มีเลย__ () แต่มันจะมีพฤติกรรมเหมือนรายการมากขึ้นหรือน้อยลง (แม้จะกำหนด "__setitem ") คุณสามารถย้ำองค์ประกอบของมันได้ดี ฟังก์ชัน len () ใช้งานได้และคุณสามารถจัดทำดัชนีองค์ประกอบ ฉันพยายามหาชุดค่าผสมที่เหมาะสมที่ดึงดูดรายการทุกประเภท แต่ไม่รวมสตริง ฉันคิดว่าฉันจะชำระสำหรับการตรวจสอบที่ " getitem " และ " len " ในขณะที่แยก basestring อย่างชัดเจน
haridsv

5

นี่ไม่ได้ตั้งใจจะตอบ OP โดยตรง แต่ฉันต้องการแบ่งปันแนวคิดที่เกี่ยวข้อง

ฉันสนใจคำตอบ @steveha ด้านบนมากซึ่งดูเหมือนจะยกตัวอย่างว่าการพิมพ์เป็ดดูเหมือนจะแตก ในความคิดที่สองอย่างไรก็ตามตัวอย่างของเขาแสดงให้เห็นว่าการพิมพ์เป็ดนั้นยากที่จะทำตาม แต่ก็ไม่แนะนำว่าstrควรมีการจัดการเป็นพิเศษ

strท้ายที่สุดแล้วชนิดที่ไม่ใช่(เช่นชนิดที่ผู้ใช้กำหนดเองที่รักษาโครงสร้างแบบเรียกซ้ำที่ซับซ้อน) อาจทำให้sreprฟังก์ชัน@steveha ทำให้เกิดการเรียกซ้ำแบบไม่สิ้นสุด แม้ว่าสิ่งนี้จะไม่น่ายอมรับ แต่เราก็ไม่สามารถเพิกเฉยต่อความเป็นไปได้นี้ได้ ดังนั้นแทนที่จะพิเศษปลอกstrในsreprเราควรจะชี้แจงสิ่งที่เราต้องการsreprจะทำอย่างไรเมื่อผลการเรียกซ้ำอนันต์

อาจดูเหมือนว่าวิธีการหนึ่งที่สมเหตุสมผลคือการทำลายการสอบถามซ้ำในsreprเวลาlist(arg) == [arg]นั้น นี้จะในความเป็นจริงอย่างสมบูรณ์แก้ปัญหาด้วยโดยไม่ต้องใด ๆstrisinstance

อย่างไรก็ตามโครงสร้างแบบเรียกซ้ำที่ซับซ้อนจริงๆอาจทำให้เกิดการวนซ้ำไม่สิ้นสุดที่list(arg) == [arg]ไม่เคยเกิดขึ้น ดังนั้นในขณะที่การตรวจสอบข้างต้นมีประโยชน์ แต่ก็ไม่เพียงพอ เราต้องการบางสิ่งที่เหมือนขีด จำกัด อย่างหนักต่อความลึกในการเรียกซ้ำ

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


1
อืมฉันชอบวิธีที่คุณคิด ฉันคิดว่าคุณไม่สามารถยืนยันได้ว่ารหัสของฉันเป็นจริง: มีกรณีทั่วไปหนึ่งกรณีstrเท่านั้นที่รหัสกรณีพิเศษจัดการ แต่อาจจะมีคุณสมบัติมาตรฐานใหม่ที่โค้ดสามารถตรวจสอบ.__atomic__ได้กล่าวว่าเป็นสัญญาณว่าบางสิ่งไม่สามารถแยกย่อยได้อีก มันอาจจะสายเกินไปที่จะเพิ่มฟังก์ชั่นบิวด์อินอื่นatomic()ลงใน Python แต่บางทีเราอาจเพิ่มfrom collections import atomicหรืออะไรก็ได้
steveha

5

ผมพบว่าฟังก์ชั่นที่มีชื่อเช่นis_sequence ใน tensorflow

def is_sequence(seq):
  """Returns a true if its input is a collections.Sequence (except strings).
  Args:
    seq: an input sequence.
  Returns:
    True if the sequence is a not a string and is a collections.Sequence.
  """
  return (isinstance(seq, collections.Sequence)
and not isinstance(seq, six.string_types))

และฉันได้ตรวจสอบแล้วว่ามันตรงกับความต้องการของคุณ


2

ฉันทำสิ่งนี้ในผลงานของฉัน

def assertIsIterable(self, item):
    #add types here you don't want to mistake as iterables
    if isinstance(item, basestring): 
        raise AssertionError("type %s is not iterable" % type(item))

    #Fake an iteration.
    try:
        for x in item:
            break;
    except TypeError:
        raise AssertionError("type %s is not iterable" % type(item))

ฉันคิดว่าคุณถูกปล่อยให้อยู่ใน 'ผลผลิต' ถัดไปหากผ่านไปในเครื่องกำเนิดไฟฟ้า แต่แล้วอีกครั้งนี่คือ 'unittest'


2

ในลักษณะ "การพิมพ์เป็ด" วิธีการเกี่ยวกับ

try:
    lst = lst + []
except TypeError:
    #it's not a list

หรือ

try:
    lst = lst + ()
except TypeError:
    #it's not a tuple

ตามลำดับ สิ่งนี้จะหลีกเลี่ยงสิ่งที่isinstance/ hasattrวิปัสสนา

คุณสามารถตรวจสอบในทางกลับกัน:

try:
    lst = lst + ''
except TypeError:
    #it's not (base)string

ตัวแปรทั้งหมดไม่ได้เปลี่ยนเนื้อหาของตัวแปร แต่เป็นการกำหนดใหม่ ฉันไม่แน่ใจว่าสิ่งนี้อาจไม่เป็นที่พึงปรารถนาในบางสถานการณ์

ที่น่าสนใจด้วยการมอบหมาย "ในสถานที่" จะ+=ไม่มีการTypeErrorยกในกรณีใด ๆ หากlstเป็นรายการ (ไม่ใช่tuple ) นั่นเป็นสาเหตุที่การบ้านทำแบบนี้ บางทีใครบางคนสามารถทำให้เข้าใจว่าทำไมถึงเป็นเช่นนั้น


1

วิธีที่ง่ายที่สุด ... ใช้anyและisinstance

>>> console_routers = 'x'
>>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)])
False
>>>
>>> console_routers = ('x',)
>>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)])
True
>>> console_routers = list('x',)
>>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)])
True

1

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

การแทนค่าสตริงของวัตถุที่มีลักษณะคล้ายสตริงนั้นเป็นสตริงเองดังนั้นคุณสามารถตรวจสอบว่าคุณได้รับออบเจ็กต์ที่เท่ากันจากตัวstrสร้างหรือไม่:

# If a string was passed, convert it to a single-element sequence
if var == str(var):
    my_list = [var]

# All other iterables
else: 
    my_list = list(var)

สิ่งนี้ควรจะใช้ได้กับทุกวัตถุที่เข้ากันได้strและสำหรับวัตถุที่ทำซ้ำได้ทุกชนิด


0

Python 3 มีสิ่งนี้:

from typing import List

def isit(value):
    return isinstance(value, List)

isit([1, 2, 3])  # True
isit("test")  # False
isit({"Hello": "Mars"})  # False
isit((1, 2))  # False

ดังนั้นเพื่อตรวจสอบทั้งรายการและสิ่งอันดับมันจะเป็น:

from typing import List, Tuple

def isit(value):
    return isinstance(value, List) or isinstance(value, Tuple)

0
assert (type(lst) == list) | (type(lst) == tuple), "Not a valid lst type, cannot be string"

2
นี่เป็นวิธีที่ใช้ได้หรือไม่?
ersh

1
ยินดีต้อนรับสู่ SO คำอธิบายว่าทำไมรหัสนี้ตอบคำถามจะเป็นประโยชน์
นิค

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

-1

เพิ่งทำสิ่งนี้

if type(lst) in (list, tuple):
    # Do stuff

5
isinstance (lst, (list, tuple))
Davi Lima

@DaviLima ตกลงนั่นเป็นอีกวิธีหนึ่ง แต่แนะนำให้ใช้ type () สำหรับประเภทที่สร้างขึ้นและ isinstance สำหรับคลาส
ATOzTOA

-1

ในหลาม> 3.6

import collections
isinstance(set(),collections.abc.Container)
True
isinstance([],collections.abc.Container)
True
isinstance({},collections.abc.Container)
True
isinstance((),collections.abc.Container)
True
isinstance(str,collections.abc.Container)
False

2
ในการตรวจสอบครั้งสุดท้ายที่คุณใช้ประเภทstrไม่ใช่สตริง ลองและคุณจะเห็นว่ามันจะกลับมาisinstance('my_string', collections.abc.Container) Trueนี้เป็นเพราะabc.Containerวัสดุ__contains__วิธีการและสตริงมีมันแน่นอน
Georgy

-6

ฉันมักจะทำสิ่งนี้ (ถ้าฉันต้องทำจริงๆ):

for i in some_var:
   if type(i) == type(list()):
       #do something with a list
   elif type(i) == type(tuple()):
       #do something with a tuple
   elif type(i) == type(str()):
       #here's your string

5
คุณแทบไม่ควรทำเช่นนี้ จะเกิดอะไรขึ้นถ้าผมsome_varเป็นตัวอย่างของการเรียนที่เป็น subclass ของlist()? รหัสของคุณจะไม่มีความคิดว่าจะทำอย่างไรกับมันแม้ว่ามันจะทำงานอย่างสมบูรณ์แบบภายใต้รหัส "ทำบางสิ่งบางอย่างกับรายการ" และคุณไม่จำเป็นต้องใส่ใจกับความแตกต่างระหว่างรายการและทูเปิล ขออภัย -1
steveha

1
ไม่จำเป็นต้องเขียนtype(tuple())- tupleจะทำ เหมือนกันสำหรับรายการ นอกจากนี้ทั้งstrและunicodeขยายbasestringซึ่งเป็นชนิดสตริงจริงดังนั้นคุณต้องการตรวจสอบว่าแทน
รักษา mods ของคุณให้ดี

@DBBloodmoney: downvote โดยอุบัติเหตุ โปรดแก้ไขคำตอบของคุณ (เล็กน้อย) เพื่อให้ฉันลบ downvote
SabreWolfy

ความเท่าเทียมไม่เหมือนการเปรียบเทียบความหมายสำหรับฉัน type(i) is listฉันต้องการทดสอบตัวตนแทน: นอกจากนี้ยังtype(list())เป็นเพียงlistตัวของมันเอง ... ในที่สุดมันก็ไม่ได้ผลกับคลาสย่อย หากiอยู่ในความเป็นจริงและ OrderedDict หรือชื่อ tuple บางชนิดรหัสนี้จะถือว่าเป็นสตริง
bukzor
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.