มันมีหลาย ๆ กรณีเช่นหากโค้ดส่วนหนึ่งของเราเจอปัญหา อาจจะเกิด error ขึ้นแล้ว exception handler ของเราจับได้ หากว่าปัญหานี้สามารถแก้ได้ด้วยการ “ลองอีกครั้ง”​ เราก็อาจจะต้องแก้ปัญหาด้วยวิธีการวน loop ครอบไว้ส่วนของโค้ดนี้ เช่น

while True:
    try:
        ... do stuff ...
        break
    except Exception:
        continue

ซึ่งก็จะทำงานได้ตามปรกติ … แต่สำหรับผมแล้วผมมองว่ามันอ่านเข้าใจได้ยาก เพราะการใช้ while loop นั่นเอง .. มันไม่ได้บอกเราตรง ๆ ว่าเรากำลังจะทำอะไร คนอ่านจะต้อง “อ่านโค้ดให้หมด”​ จึงจะเข้าใจสิ่งที่เราทำ แล้วเราก็อาจจะพลาดการใส่ break ตอนสุดท้ายของโค้ดไปได้ง่าย ๆ … ซึ่งไม่ดีเลย

ผมเลยลองหาวิธีใหม่ที่น่าจะงดงามกว่านี้ ควรจะอ่านเป็นภาษาอังกฤษแล้วเข้าใจได้เลย แล้วก็ทนทานต่อปัญหาหยุมหยิบแบบนี้มากกว่านี้ (ก็ไม่รู้เหมือนกันว่าวิธีที่เสอนนี่จะดีขนาดไหน) ซึ่งก็จะได้เป็น function decorator แบบนี้ครับ

def autorun(fn):
    def rerun():
        wrapper(rerun)

    def wrapper(rerun):
        fn(rerun)

    wrapper(rerun)

    return wrapper

decorator นี้ชื่อว่า autorun ซึ่งต้องการ function ที่รับ parameter 1 ตัว ซึ่งก็คือ function สำหรับรันตัวเองอีกครั้ง ลองดูวิธีการใช้งานเลยดีกว่า

shared = {'a': 0}

@autorun
def _(retry):
    print('rerun')
    shared['a'] += 1
    if shared['a'] < 10:
        retry()

assert shared['a'] == 10

ผมได้ลองสร้างฟังก์ชันไร้นาม _ ขึ้นมาหนึ่งตัวแล้วก็ใส่ decorator ให้มันเสีย ซึ่งจะเห็นจากโค้ดได้ว่าฟังก์ชัน _ ถูกรันเองเลยเราไม่ต้องไปสั่งให้มันทำงานตรง ๆ แต่อย่างใด

ถ้าเขียนเป็นโค้ดโดยทั่วไปก็จะเป็นแบบนี้

@autorun
def _(retry):
    try:
        ... do stuff ...
    except Exception:
        retry()

หวังว่านี่น่าจะงดงามขึ้นกว่าอันเดิมที่ใช้ while loop นะครับ ๕๕๕