คุณ ppthera อธิบาย yield ของ Ruby ไว้น่าสนใจที่ http://www.codenone.com/node/21 เลยถือโอกาสนี้อธิบายคำเดียวกันใน Python บ้าง Python ก็มี yield แต่แทบจะต่างกันโดยสิ้นเชิง yield ใน Python มีไว้สำหรับสร้าง generator และมันเป็นคีย์เวิร์ด
from UserList import UserList class MyList(UserList): def mycollect(self,func): for i in self.data: yield func(i) list(MyList([1,2,3]).mycollect(lambda i: i+1)) # => [2,3,4]
น่าเกลียดไปนิด เขียนแบบ Python ดีกว่า
def mycollect(l,func): for i in l: yield func(i) list(mycollect([1,2,3],lambda i: i+1)) # => [2,3,4]
สิ่งที่ได้จาก mycollect คือ generator ที่มี next() ให้เรียกไปเรื่อยๆ จนเจอ None ใน BitTorrent เอา yield มาใช้สำหรับเก็บ state ของโปรโตคอล ว่าแต่ ความสวยงามสู้ไม่ได้เลยแฮะ
กระทู้เก่าๆ จะย้ายตามไปในภายหลัง ตอนนี้ปิดการโพสต์กระทู้ไว้ เหลือไว้เฉพาะอ้างอิงเท่านั้น
ผมว่า yield ใน Python มันไม่ได้มีเป้าหมายเดียวกันกับใน Ruby เลยเวลาเอามาเขียนงานเดียวกัน (เช่นแบบ ใน mycollect) แล้วมันเลยดูสวยไม่เท่ากัน
เช่น ใน Python อยากจะทำแบบ mycollect ก็อาจเขียนง่าย ๆ แค่นี้ก็พอ (ไม่ต้องใช้ yield)
def mycollect2(l,f): r = [] for i in l: r.append(f(i)) return r >>> mycollect2([1,2,3], lambda i:i+1) # => [2, 3, 4]แต่ ถ้าเขียนโดยใช้ yield มันจะเหมือน เขียนฟังก์ชันที่ return ของที่เรียกเอามาต่อได้เรื่อย ๆ ฟังก์ชันจะทำงาน ๆ หยุด ๆ ได้ เอาไปใช้อะไรได้อีกหลายอย่าง เช่น เราสามารถเอา mycollect ของคุณ sugree มาเขียนประมาณนี้ได้ (ซึ่งผมเห็นครั้งแรก นี่ผมทึ่งมาก)
>>> a = [] >>> for i in mycollect([1,2,3,4],lambda i:i*i): if i>5: a.append(i) >>> a # => [9,16]ทีนี้เวลาในการทำงานจริง ๆ ฟังก์ชัน mycollect เราจะเหมือนโดนเรียกแล้วจะทำงานแล้วก็หยุด ทำงานแล้วก็หยุด ไปเรื่อย ๆ (คือหยุดตอน yield) แล้วพอโดนเรียก ด้วย next() ซึ่ง for จะเป็นคนเรียก function เราก็จะทำงานต่อ
(ถ้าเข้าใจไม่ผิด... นี่น่าจะเป็นรูปแบบหนึ่งของการใช้ continuation)
ใน rubygarden ก็มีคนเขียนอธิบายไว้เหมือนกันครับ
ว่าถ้าถ้าอยากใช้ generator แบบ python
ก็ให้ใช้วิธีนี้
เขียนเป็น ruby
โดย Generate class ใช้ Contination ในการ implement
พอทำแบบนี้เหมือนมันจะ "ไม่ชัด" ว่าจะหยุดการทำงานแล้วนะ...
แต่ที่มันทำได้โดยไม่ต้องเป็น "ส่วนหนึ่ง" ของภาษา นี่น่าสนใจมากอ่ะครับ
ครับใน Python เรียกว่า Simple Generator รู้สึก Java ก็มีนี่
ผมว่าเท่มาก ๆ
เท่กว่า yield ของ ruby อีก (อันนั้นมันเหมือน แบบ ส่ง block มาให้ โดยไม่ต้องประกาศ argument อีกต่างหาก...)
จริง ๆ น่าจะมีความหมายบางอย่างเหมือนกัน... สงสัยต้องถามคุณ ppthera
lambda ของ Python มีได้แค่บรรทัดเดียว และจะไม่มีวันมีเกินบรรทัดเดียวด้วย บางคนชอบ lambda ถึงกับเถียงกันใหญ่โต อยากให้มีหลายบรรทัด สุดท้ายประเด็นก็ตกไป จน lambda เกือบโดนลบทิ้งเพราะมันไม่งาม แต่สุดท้ายก็ยังมีอยู่เหมือนเดิม
ของ Ruby ดูสะดวกดี โค้ดสั้นๆ ไม่ต้องไปเขียนฟังก์ชั่นเป็นตัวเป็นตน อืมแต่มันเป็นคำเดียวกันต่างจุดประสงค์จริงๆ
เหมือนกับคำว่า *yield* จะมีตำนาน ใครพอทราบบ้างครับ
ผมก็เคยสงสัยเหมือนกันว่า wording "yield" ที่ Mat (คนออกแบบ ruby) เลือกใช้
มีที่มาจากไหน
(เพราะตอนนั้นก็เริ่มเห็นแล้วว่า python มี yield ทีี่คนละความหมายกัน)
ไว้จะลองค้นดูบ้างครับ
ไปกด ๆ หามาครับ (จริง ๆ น่าเอาไปไว้ที่ forum ของ ruby)
Programming-language buffs will be pleased to know that the keyword yield was chosen to echo the yield function in Liskov's language CLU, a language that is over 20 years old and yet contains features that still haven't been widely exploited by the CLU-less.
จาก http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_containers.html
อืมม์ ใน python mailing list เขียนไว้แบบนี้
อ่านไปอ่านมา พบว่า
Yield ใน Python เนี่ยะ จะเป็นลักษณะเดียวกันกับในภาษา CLU
ส่วนของ ruby จะเป็นคนละแบบ (คือกลับหัวกลับหางกัน)
อ่านรายละเอียด จาก http://mjtsai.com/blog/2003/03/30/iterators/
เป็นคำที่มีประวัติยาวนานจริงๆ รากเหง้าเดียวกัน แต่ดันตรงข้ามกัน เอาไว้สำหรับคนที่เขียน 2 ภาษานี้พร้อมกันให้ธาตุไฟเข้าแทรกเล่นๆ
java ไม่มี concept generator แบบ python ครับ