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

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

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

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

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

ارور عجیب در پایتون ۲

دوشنبه, ۱۵ دی ۱۳۹۳، ۰۴:۰۷ ب.ظ

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

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

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:

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


موافقین ۰ مخالفین ۰ ۹۳/۱۰/۱۵
سعید رسولی

نظرات  (۴)

سعید جان لطفا باگ ریپورت
پاسخ:
باگ در چی؟
اگه منظورتون باگ در پایتون هست، به این نمیشه گفت باگ، در واقع یک نوع ابهام هست در سینتکس پایتون ۲، که در پایتون ۳ برطرف شده. پس خودشون از مدت‌ها قبل خبر داشتن و نیازی به گزارش نیست.
یه نکته ای که من در نوشته های شما دریافته‌ام میزان حوصله ای هست که در انتقال موضوع و مفهوم به مخاطب با ذکر جزییات و مثال‌ها به خرج می دهید و از این منظر جای تحسین و تشکر داره. کاش این صفت نیکو در آدمها بیشتر رواج داشت.
پاسخ:
ممنون صابر جان، لطف دارید
۱۸ دی ۹۳ ، ۲۱:۴۷ امیرحسین حسنینی
جالب بود. ممنون سعید جان :)
پاسخ:
خواهش می‌کنم عزیز :)
۱۳ آذر ۹۴ ، ۱۷:۴۴ فاروق کریمی زاده
جالبه.

ارسال نظر

کاربران بیان میتوانند بدون نیاز به تأیید، نظرات خود را ارسال کنند.
اگر قبلا در بیان ثبت نام کرده اید لطفا ابتدا وارد شوید، در غیر این صورت می توانید ثبت نام کنید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">