ตัวทำซ้ำของ Python ไม่มีhasNext
วิธีหรือไม่
ตัวทำซ้ำของ Python ไม่มีhasNext
วิธีหรือไม่
คำตอบ:
unnext()
next()
yield
หรือไม่) มันเป็นของแน่นอนไม่ยากที่จะเขียนอะแดปเตอร์ที่เก็บผลมาจากการnext()
ให้บริการและhas_next()
move_next()
hasNext()
วิธีการ (ผลิตแคชและคืนค่าจริงเมื่อสำเร็จหรือคืนเท็จเมื่อล้มเหลว) จากนั้นทั้งสองhasNext()
และnext()
จะขึ้นอยู่กับวิธีการทั่วไปgetNext()
และรายการแคช ฉันไม่เห็นว่าทำไมnext()
ไม่ควรอยู่ในไลบรารี่มาตรฐานหากใช้งานอะแดปเตอร์ที่ให้มาได้ง่าย
next()
และhasNext()
วิธีการของไลบรารีใด ๆไม่ใช่เพียงแค่ไลบรารี Python แบบสมมุติฐาน) ดังนั้นใช่next()
และhasNext()
จะกลายเป็นเรื่องยุ่งยากหากเนื้อหาของกระแสการสแกนขึ้นอยู่กับเมื่อองค์ประกอบที่จะอ่าน
มีทางเลือกที่จะเป็นได้โดยใช้StopIteration
next(iterator, default_value)
สำหรับ exapmle:
>>> a = iter('hi')
>>> print next(a, None)
h
>>> print next(a, None)
i
>>> print next(a, None)
None
ดังนั้นคุณสามารถตรวจหาNone
หรือค่าอื่น ๆ ที่ระบุไว้ล่วงหน้าสำหรับการสิ้นสุดของตัววนซ้ำหากคุณไม่ต้องการวิธีการยกเว้น
sentinel = object()
และและการทดสอบด้วยnext(iterator, sentinel)
is
unittest.mock.sentinel
วัตถุในตัวที่ช่วยให้คุณเขียนอย่างชัดเจนnext(a, sentinel.END_OF_ITERATION)
แล้วif next(...) == sentinel.END_OF_ITERATION
หากคุณจริงๆต้องhas-next
การทำงาน (เพราะคุณเพียงแค่นับถือถ่ายทอดขั้นตอนวิธีการจากการดำเนินงานที่อ้างอิงใน Java พูดหรือเพราะคุณเขียนต้นแบบที่จะต้องมีการคัดลอกได้อย่างง่ายดายเพื่อ Java เมื่อมันเสร็จแล้ว) มันเป็นเรื่องง่ายที่จะ รับกับคลาส wrapper เล็กน้อย ตัวอย่างเช่น:
class hn_wrapper(object):
def __init__(self, it):
self.it = iter(it)
self._hasnext = None
def __iter__(self): return self
def next(self):
if self._hasnext:
result = self._thenext
else:
result = next(self.it)
self._hasnext = None
return result
def hasnext(self):
if self._hasnext is None:
try: self._thenext = next(self.it)
except StopIteration: self._hasnext = False
else: self._hasnext = True
return self._hasnext
ตอนนี้สิ่งที่ต้องการ
x = hn_wrapper('ciao')
while x.hasnext(): print next(x)
ส่งเสียง
c
i
a
o
ตามความจำเป็น.
โปรดทราบว่าการใช้ next(sel.it)
ในตัวต้องใช้ Python 2.6 หรือดีกว่า หากคุณใช้ Python เวอร์ชันเก่าให้ใช้self.it.next()
แทน (และคล้ายกันnext(x)
ในการใช้ตัวอย่าง) [[คุณอาจคิดว่าข้อความนี้ซ้ำซ้อนเนื่องจาก Python 2.6 มีมานานกว่าหนึ่งปีแล้ว - แต่บ่อยครั้งกว่าที่ฉันไม่ใช้ฟีเจอร์ Python 2.6 ในการตอบกลับผู้วิจารณ์หรือผู้อื่นรู้สึกผูกพันกับหน้าที่เพื่อชี้ให้เห็น ว่ามันเป็นฟีเจอร์ 2.6 ดังนั้นฉันจึงพยายามขัดขวางความคิดเห็นดังกล่าวเพียงครั้งเดียว ;-)]]
has_next
วิธีการ การออกแบบของ Python ทำให้เป็นไปไม่ได้ที่จะพูดใช้filter
เพื่อตรวจสอบว่าอาร์เรย์มีองค์ประกอบที่ตรงกับภาคแสดงหรือไม่ ความเย่อหยิ่งและความสายตาสั้นของชุมชน Python กำลังส่าย
TypeError: iter() returned non-iterator
map
และany
แทนfilter
แต่คุณสามารถใช้SENTINEL = object(); next(filter(predicate, arr), SENTINEL) is not SENTINEL
หรือลืมSENTINEL
และใช้เพียงและจับtry: except
StopIteration
นอกจากการกล่าวถึง StopIteration ทั้งหมดแล้ว Python "for" loop ยังทำสิ่งที่คุณต้องการ:
>>> it = iter("hello")
>>> for i in it:
... print i
...
h
e
l
l
o
ลองใช้วิธี __length_hint __ () จากวัตถุตัววนซ้ำใด ๆ :
iter(...).__length_hint__() > 0
__init__
และ __main__
? อิมโฮมันยุ่งเหยิงไปไม่ว่าคุณจะให้เหตุผลอะไรก็ตาม
hasNext
ค่อนข้างแปลเป็นStopIteration
ข้อยกเว้นเช่น:
>>> it = iter("hello")
>>> it.next()
'h'
>>> it.next()
'e'
>>> it.next()
'l'
>>> it.next()
'l'
>>> it.next()
'o'
>>> it.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
StopIteration
docs: http://docs.python.org/library/exceptions.html#exceptions.StopIterationคุณสามารถtee
ใช้ตัววนซ้ำitertools.tee
และตรวจสอบStopIteration
ตัวเอียงตัวเอียง
ไม่แนวคิดที่คล้ายกันมากที่สุดน่าจะเป็นข้อยกเว้น StopIteration
ฉันเชื่อว่าหลามเพิ่งมีถัดไป () และตามเอกสารมันโยนข้อยกเว้นคือไม่มีองค์ประกอบเพิ่มเติม
กรณีการใช้งานที่ทำให้ฉันค้นหาสิ่งต่อไปนี้
def setfrom(self,f):
"""Set from iterable f"""
fi = iter(f)
for i in range(self.n):
try:
x = next(fi)
except StopIteration:
fi = iter(f)
x = next(fi)
self.a[i] = x
โดยที่ hasnext () พร้อมใช้งานหนึ่งสามารถทำได้
def setfrom(self,f):
"""Set from iterable f"""
fi = iter(f)
for i in range(self.n):
if not hasnext(fi):
fi = iter(f) # restart
self.a[i] = next(fi)
สิ่งที่ฉันสะอาดกว่า เห็นได้ชัดว่าคุณสามารถแก้ไขปัญหาต่าง ๆ ได้โดยการกำหนดคลาสยูทิลิตี้ แต่สิ่งที่เกิดขึ้นคือคุณมีวิธีแก้ปัญหาที่เทียบเท่ากันเกือบยี่สิบแบบที่แตกต่างกันสองแบบด้วยกัน มีหลายอย่างที่ใกล้เคียงกันในแอปพลิเคชั่นเดียวของคุณหรือเลือกผ่านและเขียนรหัสใหม่เพื่อใช้วิธีการเดียวกัน 'ทำครั้งเดียวและทำมันได้ดี' maxim ล้มเหลวไม่ดี
นอกจากนี้ตัววนซ้ำเองจำเป็นต้องมีการตรวจสอบ 'hasnext' ภายในเพื่อเรียกใช้เพื่อดูว่าจำเป็นต้องเพิ่มข้อยกเว้นหรือไม่ การตรวจสอบภายในนี้จะถูกซ่อนไว้เพื่อที่จะต้องมีการทดสอบโดยพยายามรับรายการจับข้อยกเว้นและเรียกใช้ตัวจัดการถ้าโยน นี่เป็นการซ่อนที่ไม่จำเป็นของ IMO
วิธีที่แนะนำคือStopIteration โปรดดูตัวอย่างฟีโบนักชีจากtutorialspoint
#!usr/bin/python3
import sys
def fibonacci(n): #generator function
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(5) #f is iterator object
while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()
วิธีที่ฉันแก้ไขปัญหาของฉันคือการนับจำนวนของวัตถุที่วนซ้ำจนถึงตอนนี้ ฉันต้องการวนซ้ำชุดโดยใช้การเรียกไปยังวิธีการอินสแตนซ์ เนื่องจากฉันรู้ว่าความยาวของฉากและจำนวนของสิ่งของนับจนถึงตอนนี้ฉันจึงมีhasNext
วิธีการอย่างมีประสิทธิภาพ
รหัสง่าย ๆ ของฉัน:
class Iterator:
# s is a string, say
def __init__(self, s):
self.s = set(list(s))
self.done = False
self.iter = iter(s)
self.charCount = 0
def next(self):
if self.done:
return None
self.char = next(self.iter)
self.charCount += 1
self.done = (self.charCount < len(self.s))
return self.char
def hasMore(self):
return not self.done
แน่นอนตัวอย่างคือของเล่นชิ้นหนึ่ง แต่คุณเข้าใจแล้ว สิ่งนี้จะไม่ทำงานในกรณีที่ไม่มีวิธีที่จะทำให้ความยาวของ iterable เหมือนเครื่องกำเนิดไฟฟ้าเป็นต้น