มันหมายความว่าอะไรถ้าวัตถุ Python นั้น“ ย่อยได้” หรือไม่?


คำตอบ:


356

โดยทั่วไปหมายความว่าวัตถุใช้__getitem__()วิธีการ มันอธิบายถึงวัตถุที่เป็น "ภาชนะบรรจุ" ซึ่งหมายถึงวัตถุเหล่านั้นมีวัตถุอื่น ซึ่งรวมถึงสตริงรายการสิ่งอันดับและพจนานุกรม


2
จะเชื่อถือได้เพียงใด: hasattr(SomeClassWithoutGetItem, '__getitem__')เพื่อตรวจสอบว่าสิ่งใดที่สามารถถอดได้
jmunsch

2
[... ]ไวยากรณ์การจัดทำดัชนีที่เรียกว่าห้อยเพราะมันเทียบเท่ากับสัญกรณ์คณิตศาสตร์ที่ใช้ห้อยจริง เช่นa[1]เป็นงูหลามสำหรับสิ่งที่นักคณิตศาสตร์จะเขียนเป็นa₁ ดังนั้น "ห้อยได้" หมายถึง "สามารถห้อยได้" ซึ่งในแง่หลามหมายความว่ามีการดำเนินการ__getitem__()เนื่องจากเป็นเพียงน้ำตาลประโยคสำหรับa[1] a.__getitem__(1)
Mark Reed

การโทรhasattrนั้นควรจะทำงานได้ดี แต่ไม่ใช่วิธี Pythonic ในการทำสิ่งต่าง ๆ ปฏิบัติหลามกระตุ้นให้เกิดการพิมพ์ดีดเป็ด หมายความว่าถ้าคุณวางแผนที่จะดึงรายการจากวัตถุของคุณโดยใช้ตัวห้อยไปข้างหน้าและทำมัน ถ้าคุณคิดว่ามันอาจจะไม่ทำงานเพราะวัตถุไม่ได้ subscriptable ห่อไว้ใน บล็อกที่มีtry except TypeError
Mark Reed

77

จากด้านบนของหัวของฉันต่อไปนี้เป็นบิวด์อินเท่านั้นที่สามารถถอดได้:

string:  "foobar"[3] == "b"
tuple:   (1,2,3,4)[3] == 4
list:    [1,2,3,4][3] == 4
dict:    {"a":1, "b":2, "c":3}["c"] == 3

แต่คำตอบของ mipadiนั้นถูกต้อง - คลาสใด ๆ ที่ดำเนินการ__getitem__นั้นสามารถห้อยได้


17

วัตถุที่สามารถสคริปต์ได้เป็นวัตถุที่บันทึกการดำเนินการที่ทำไว้และสามารถจัดเก็บไว้เป็น "สคริปต์" ซึ่งสามารถเล่นซ้ำได้

ตัวอย่างเช่นดู: Application Scripting Framework

ทีนี้ถ้าอลิสแตร์ไม่รู้สิ่งที่เขาถามและหมายถึงวัตถุ "ที่สามารถอธิบายได้" (แก้ไขโดยผู้อื่น) ดังนั้นจากนั้น (ตามที่ mipadi ตอบด้วย) นี่คือสิ่งที่ถูกต้อง:

ออบเจกต์แบบห้อยได้คือวัตถุใด ๆ ที่ใช้__getitem__วิธีพิเศษ (คิดว่าเป็นรายการพจนานุกรม)


2
โปรดทราบว่าฉันกำลังตอบคำถามเดิมเกี่ยวกับวัตถุ "scriptable" ไม่ใช่ "subscriptable" ที่แก้ไขโดยผู้อื่นไม่ใช่ Alistair ฉันอยากให้อลิสแตร์แสดงความคิดเห็น
tzot

อาป้ายใหม่สำหรับคอลเลกชันของฉัน! :) แค่ล้อเล่นแน่ ๆ สิ่งเดียวที่เป็นธรรมในการแก้ไขคำถามคืออลิสแตร์เลือกคำตอบ ฉันยังไม่แน่ใจว่า Alistair แน่ใจหรือไม่เกี่ยวกับการเลือก
tzot

16

ความหมายของตัวห้อยในการคำนวณคือ: "สัญลักษณ์ (เขียนโดยความคิดในฐานะตัวห้อย แต่โดยปกติแล้วไม่ได้ใช้) ในโปรแกรมเพียงอย่างเดียวหรือกับคนอื่น ๆ เพื่อระบุองค์ประกอบหนึ่งของอาเรย์"

ตอนนี้ในตัวอย่างง่ายๆที่กำหนดโดย@ user2194711เราจะเห็นว่าองค์ประกอบต่อท้ายไม่สามารถเป็นส่วนหนึ่งของรายการเนื่องจากเหตุผลสองประการ: -

1) เราไม่ได้เรียกวิธีการต่อท้ายจริงๆ เพราะมันต้อง()เรียกมัน

2) ข้อผิดพลาดจะแสดงว่าฟังก์ชั่นหรือวิธีการไม่สามารถห้อยได้; หมายความว่าพวกเขาไม่สามารถจัดทำดัชนีเช่นรายการหรือลำดับ

ตอนนี้ดูสิ่งนี้: -

>>> var = "myString"
>>> def foo(): return 0
... 
>>> var[3]
't'
>>> foo[3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'function' object is not subscriptable

ซึ่งหมายความว่าไม่มีตัวห้อยหรือพูดว่าองค์ประกอบfunctionเหมือนเกิดขึ้นในลำดับ; []และเราไม่สามารถเข้าถึงได้เหมือนที่เราทำด้วยความช่วยเหลือของ

นอกจากนี้ยัง; ดังที่mipadiพูดในคำตอบของเขา; โดยทั่วไปหมายความว่าวัตถุใช้__getitem__()วิธีการ (ถ้ามันสามารถ subscriptable) ดังนั้นข้อผิดพลาดที่ผลิต:

arr.append["HI"]

TypeError: วัตถุ 'builtin_function_or_method' ไม่สามารถห้อยได้


7

ฉันมีปัญหาเดียวกันนี้ ฉันกำลังทำ

arr = []
arr.append["HI"]

ดังนั้นการใช้[ทำให้เกิดข้อผิดพลาด มันควรจะเป็นarr.append("HI")


3

ในฐานะที่เป็นข้อพิสูจน์ถึงคำตอบก่อนหน้านี้ที่นี่บ่อยครั้งมากนี่เป็นสัญญาณที่คุณคิดว่าคุณมีรายการ (หรือ dict หรือวัตถุอื่น ๆ ที่สามารถถอดได้) เมื่อคุณไม่ทำ

ตัวอย่างเช่นสมมติว่าคุณมีฟังก์ชันที่ควรส่งคืนรายการ

def gimme_things():
    if something_happens():
        return ['all', 'the', 'things']

ตอนนี้เมื่อคุณเรียกใช้ฟังก์ชันนั้นและsomething_happens()ด้วยเหตุผลบางอย่างไม่ส่งคืนTrueค่าจะเกิดอะไรขึ้น ความifล้มเหลวและคุณล้มเหลว gimme_thingsไม่ชัดเจนreturnอะไร - return Noneเป็นอย่างนั้นในความเป็นจริงมันจะโดยปริยาย จากนั้นรหัสนี้:

things = gimme_things()
print("My first thing is {0}".format(things[0]))

จะล้มเหลวด้วย " NoneTypeobject is subscriptable ไม่ได้" เพราะthingsก็คือNoneและคุณกำลังพยายามทำสิ่งNone[0]ที่ไม่สมเหตุสมผลเพราะ ... สิ่งที่ข้อความแสดงข้อผิดพลาดระบุ

มีสองวิธีในการแก้ไขข้อผิดพลาดนี้ในรหัสของคุณ - วิธีแรกคือการหลีกเลี่ยงข้อผิดพลาดโดยการตรวจสอบว่าใช้งานthingsได้จริงก่อนที่จะพยายามใช้

things = gimme_things()
if things:
    print("My first thing is {0}".format(things[0]))
else:
    print("No things")  # or raise an error, or do nothing, or ...

หรือเทียบเท่ากับดักTypeErrorข้อยกเว้น;

things = gimme_things()
try:
    print("My first thing is {0}".format(things[0]))
except TypeError:
    print("No things")  # or raise an error, or do nothing, or ...

อีกประการหนึ่งคือการออกแบบใหม่gimme_thingsเพื่อให้แน่ใจว่าจะส่งคืนรายการเสมอ ในกรณีนี้นั่นอาจจะเป็นการออกแบบที่เรียบง่ายกว่าเพราะมันหมายถึงถ้ามีหลายสถานที่ที่คุณมีจุดบกพร่องคล้ายกันพวกมันสามารถถูกเก็บไว้อย่างเรียบง่าย

def gimme_things():
    if something_happens():
        return ['all', 'the', 'things']
    else:  # make sure we always return a list, no matter what!
        logging.info("Something didn't happen; return empty list")
        return []

แน่นอนสิ่งที่คุณใส่ในelse:สาขาขึ้นอยู่กับกรณีการใช้งานของคุณ บางทีคุณควรเพิ่มข้อยกเว้นเมื่อsomething_happens()ล้มเหลวเพื่อทำให้ชัดเจนและชัดเจนยิ่งขึ้นว่ามีอะไรผิดพลาดจริงหรือไม่ การเพิ่มข้อยกเว้นในรหัสของคุณเองเป็นวิธีสำคัญที่จะทำให้คุณรู้ว่าเกิดอะไรขึ้นเมื่อมีบางอย่างล้มเหลว!

(โปรดสังเกตว่าการแก้ไขครั้งหลังนี้ยังไม่สามารถแก้ไขข้อผิดพลาดได้อย่างสมบูรณ์ - มันป้องกันคุณจากการพยายามห้อยNoneแต่things[0]ยังคงเป็นรายการที่ว่างIndexErrorเมื่อthingsคุณมีถ้าคุณมีวิธีที่tryคุณสามารถexcept (TypeError, IndexError)ดักมันได้)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.