سؤال

كنت مؤخرا التدريس نفسي الثعبان اكتشف LBYL/EAFP التعابير فيما يتعلق خطأ التحقق قبل تنفيذ التعليمات البرمجية.في بيثون ، يبدو المقبولة نمط EAFP ، ويبدو أن تعمل بشكل جيد مع اللغة.

LBYL (Look بمتهمون ، وكثيرا ما يقول Yأوو Leap):

def safe_divide_1(x, y):
    if y == 0:
        print "Divide-by-0 attempt detected"
        return None
    else:
        return x/y

EAFP (انها هـasier إلى Ask Forgiveness من Permission):

def safe_divide_2(x, y):
    try:
        return x/y
    except ZeroDivisionError:  
        print "Divide-by-0 attempt detected"
        return None

سؤالي هو:لم يسمع حتى من استخدام EAFP الأساسي التحقق من صحة البيانات بناء قادمة من Java و C++ الخلفية.هو EAFP شيئا من الحكمة أن تستخدم في جافا ؟ أم أن هناك الكثير من النفقات العامة من استثناءات ؟ وأنا أعلم أن هناك فقط النفقات العامة عند استثناء طرح فعلا, لذلك أنا غير متأكد لماذا أبسط طريقة EAFP لا تستخدم.هل هو مجرد الأفضلية ؟

هل كانت مفيدة؟

المحلول

شخصيا, وأعتقد أن هذا هو تدعمها الاتفاقية ، EAFP أبدا وسيلة جيدة للذهاب.يمكنك أن ننظر إليها باعتبارها يعادل التالية:

if (o != null)
    o.doSomething();
else
    // handle

بدلا من:

try {
    o.doSomething()
}
catch (NullPointerException npe) { 
    // handle
}

وعلاوة على ذلك يجب مراعاة ما يلي:

if (a != null)
    if (b != null)
        if (c != null)
            a.getB().getC().doSomething();
        else
            // handle c null
    else
        // handle b null
else
    // handle a null

هذا قد تبدو أقل كثيرا أنيقة (ونعم هذا هو الخام على سبيل المثال - تتحمل معي) ، لكنه يتيح لك قدر أكبر من الدقة في التعامل مع الخطأ, بدلا من التفاف كل شيء في محاولة اللحاق للحصول على هذا NullPointerException, ثم محاولة لمعرفة أين و لماذا كنت حصلت عليه.

الطريقة التي أرى أنها EAFP لا ينبغي أبدا أن تستخدم ، باستثناء حالات نادرة.أيضا, منذ أن أثيرت هذه القضية: نعم المحاولة-catch لا تكبد بعض النفقات العامة حتى إذا كان لا يتم إلقاء استثناء.

نصائح أخرى

إذا كنت الوصول إلى الملفات ، EAFP هو أكثر موثوقية من LBYL ، لأن عمليات المشاركة في LBYL ليست الذرية و نظام الملفات قد تتغير بين وقت تبدو الوقت الذي قفزة.في الواقع ، فإن معيار اسم TOCTOU - وقت الاختيار ووقت الاستخدام ؛ الأخطاء الناجمة عن غير دقيقة التحقق من TOCTOU البق.

النظر في إنشاء ملف مؤقت يجب أن يكون اسم فريد.أفضل طريقة لمعرفة ما إذا كان اختيار اسم الملف موجود حتى الآن هو محاولة خلق له - التأكد من يمكنك استخدام خيارات لضمان أن تفشل العملية إذا كان الملف موجود بالفعل (في POSIX/Unix حيث O_EXCL العلم open()).إذا كنت في محاولة لاختبار ما إذا كان الملف موجود بالفعل (ربما باستخدام access()) ، ثم بين الوقت عندما تقول "لا" و الوقت محاولة إنشاء ملف شخص أو أي شيء آخر قد قام بإنشاء الملف.

على العكس من ذلك ، افترض أن محاولة قراءة ملف موجود.الخاص بك التحقق من أن الملف موجود (LBYL) قد يقول "هناك" ، ولكن عندما كنت في الواقع فتحه تجد "ليس هناك".

في كل هذه الحالات يجب أن تحقق العملية النهائية و LBYL لم تساعد تلقائيا.

(إذا كنت تعبث مع SUID أو SGID البرامج ، access() يسأل مختلفة السؤال ؛ قد تكون ذات صلة إلى LBYL ، ولكن القانون لا يزال يجب أن تأخذ في الاعتبار إمكانية الفشل.)

بالإضافة إلى التكلفة النسبية الاستثناءات في بايثون جافا, نضع في اعتبارنا أن هناك فرق في الفلسفة / الموقف بينهما.جافا يحاول أن تكون صارمة جدا حول أنواع (و كل شيء آخر) ، والتي تتطلب صريحة مفصلة وإعلانات من فئة/طريقة التوقيعات.فإنه يفترض أن يجب أن تعرف في أي نقطة بالضبط ما هو نوع الكائن الذي تستخدمه وما هو قادر على فعله.في المقابل, بايثون "بطة الكتابة" يعني أنك لا نعرف على وجه اليقين (و لا ينبغي العناية) ما يعبر عن نوع من كائن ، تحتاج فقط إلى الرعاية التي الدجالين عندما تطلب ذلك.في هذا النوع من بيئة تسمح الوحيد عاقل الموقف هو أن نفترض أن الأمور سوف تعمل ، ولكن تكون على استعداد للتعامل مع العواقب إذا لم يفعلوا ذلك.جافا الطبيعية التقييد لا تتناسب بشكل جيد مع مثل عارضة النهج.(هذا لا يقصد منه الحط أي نهج أو اللغة ، ولكن بدلا من ذلك إلى القول بأن هذه المواقف هي جزء من كل لغة هي لغة ، والنسخ التعابير بين لغات مختلفة يمكن أن تؤدي في كثير من الأحيان إلى الاحراج وضعف التواصل...)

الاستثناءات يتم التعامل معها بشكل أكثر كفاءة في بيثون في جافا ، والتي هي على الأقل جزئيا لماذا ترى أن بناء في بيثون.في جافا, انها أكثر كفاءة (من حيث الأداء) استخدام استثناءات في هذا الطريق.

النظر في هذه التعليمات البرمجية المتكررة:

def int_or_default(x, default=0):
    if x.isdigit():
        return int(x)
    else:
        return default

def int_or_default(x, default=0):
    try:
        return int(x)
    except ValueError:
        return default

كلاهما تبدو صحيحة, صحيح ؟ ولكن واحد منهم لم يكن.

السابق ، وذلك باستخدام LBYL, فشل بسبب تمييز دقيق بين isdigit و isdecimal;عندما دعا مع سلسلة "①23🄅 ₅" ، فإنه سيتم رمي خطأ بدلا من بشكل صحيح إرجاع القيمة الافتراضية.

في وقت لاحق باستخدام EAFTP النتائج في التعامل الصحيح ، بحكم التعريف.ليس هناك مجالا في السلوك عدم تطابق لأن التعليمات البرمجية التي تحتاج متطلبات هو الرمز الذي يؤكد أن الشرط.

باستخدام LBYL يعني أخذ المنطق الداخلي و نسخها إلى كل الاتصال الموقع.بدلا من الاضطرار واحد الكنسي ترميز الاحتياجات الخاصة بك ، يمكنك الحصول على فرصة مجانية إلى الفوضى في كل مرة يتم استدعاء الدالة.

ومن الجدير بالذكر أن EAFTP لا عن الاستثناءات ، و كود جافا خاصة لا ينبغي استخدام الاستثناءات انتشارا.هو عن إعطاء الحق في العمل الحق كتلة من التعليمات البرمجية.وعلى سبيل المثال ، استخدام Optional عودة القيم وسيلة صالحة تماما من كتابة EAFTP رمز, و هو أكثر فعالية لضمان صحة من LBYL.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top