وبلاگ سعید رسولی

بخور، بخواب، کد بزن

بخور، بخواب، کد بزن

گنو/لینوکس، پایتون، زندگی

آخرین مطالب
مطالب پربحث‌تر

۱ مطلب در دی ۱۳۹۳ ثبت شده است

این یکی از عجیب‌ترین و خنده‌دارترین ارورهای پایتون هست که تا به حال بهش برخورد کردم:

(البته فقط توی پایتون ۲)

UnboundLocalError: local variable 'IndexError' referenced before assignment


و این کدی هست که اون ارور رو توی پایتون 2.7 تولید می‌کنه:

def func1():
    l = []
    d = {}
    try:
        l[0]
    except IndexError:
        print 'list item not found'
    try:
        d['a'][0]
    except KeyError, IndexError:
        print 'dict item not found'
func1()


این هم متن کامل ارور:

Traceback (most recent call last):
  File "funny-python-error.py", line 18, in <module>
    func1()
  File "funny-python-error.py", line 10, in func1
    except IndexError:
UnboundLocalError: local variable 'IndexError' referenced before assignment



اما چه چیزی باعث ایجاد این ارور شده؟ این خط:

    except KeyError, IndexError:

که از لحاظ سینتکسی درسته(توی پایتون ۲)، ولی از لحاظ منطقی کاملاً اشتباهه. و باید تغییر کنه به:

    except (KeyError, IndexError):


چون بدون پرانتزها (که tuple ایجاد می‌کنه)، علامت ویرگول به معنای as هست(که as توی 2.6 اضافه شده)، پس این دو خط معادل هم هستن:

    except KeyError, IndexError:
    except KeyError as IndexError:


که باعث میشه شیء درونی IndexError بازنویسی بشه و اتفاقات عجیب و غریب بیفته. در واقع من هنوز نمی‌دونم چرا حتی قبل از بازنویسی‌ش هم IndexError توی اون تابع ناشناخته‌س. اون ارور کذایی قبل از رسیدن به این خط داده میشه. فقط می‌دونم که اشیاء درونی پایتون از جمله IndexError نباید بازنویسی بشن، حتی اگه پایتون این اجازه رو بهمون بده


مثلاً هستن برنامه‌نویس‌هایی که متغیرهایی به اسم id یا type یا str تعریف می‌کنن که خیلی کار بدیه و باعث ایجاد مشکلات غیرمنتظره میشه. باید حداقل یه underline اول اسم این متغیرها بذاریم که با اشیاء و توابع درونی پایتون قاتی نشه.


نکتهٔ بعدی اینکه سینتکس

except KeyError as e:

توی پایتون 2.6 اضافه شده، ولی اون سینتکس قبلی

except KeyError, e:

بخاطر سازگاری، توی 2.6 و 2.7 هم پشتیبانی میشه. ولی بخاطر ابهامی که داره (که اینجور مشکلات هم نتیجهٔ این ابهام هست) توی پایتون ۳ پشتیبانی نمیشه.


یعنی توی پایتون 2.6 و 2.7 و 3 می‌تونید این‌ها رو بنویسید:

except KeyError as e:
except (KeyError, IndexError):
except (KeyError, IndexError) as e:


این رو توی پایتون 2 می‌تونید بنویسید ولی توی پایتون 3 نمی‌تونید بنویسید:

except KeyError, e:

در نتیجه اون ارور عجیب و غریب احتمالاً توی پایتون ۳ دیده نمیشه (مگه به دلیل دیگه‌ای)


۴ نظر موافقین ۰ مخالفین ۰ ۱۵ دی ۹۳ ، ۱۶:۰۷
سعید رسولی