سؤال

  1. هل هناك الأداء أو رمز صيانة المسألة مع استخدام assert كجزء من رمز القياسية بدلا من استخدامه فقط لأغراض التصحيح ؟

    هو

    assert x >= 0, 'x is less than zero'
    

    أفضل أو أسوأ من

    if x < 0:
        raise Exception, 'x is less than zero'
    
  2. أيضا, هل هناك أي طريقة لوضع قاعدة عمل مثل if x < 0 raise error أن يتم التحقق دائما من دون try/except/finally حتى, إذا في أي وقت طوال رمز x أقل من 0 خطأ يتم رفع مثل إذا قمت بتعيين assert x < 0 في بداية وظيفة, في أي مكان داخل وظيفة حيث x يصبح أقل من 0 استثناء رفعت ؟

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

المحلول

لتكون قادرا على إلقاء خطأ تلقائيا عندما تصبح X أقل من الصفر طوال الدالة. يمكنك استخدام واصفات الطبقة. وبعد هنا مثال:

class LessThanZeroException(Exception):
    pass

class variable(object):
    def __init__(self, value=0):
        self.__x = value

    def __set__(self, obj, value):
        if value < 0:
            raise LessThanZeroException('x is less than zero')

        self.__x  = value

    def __get__(self, obj, objType):
        return self.__x

class MyClass(object):
    x = variable()

>>> m = MyClass()
>>> m.x = 10
>>> m.x -= 20
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "my.py", line 7, in __set__
    raise LessThanZeroException('x is less than zero')
LessThanZeroException: x is less than zero

نصائح أخرى

يجب استخدام التأكيدات لاختبار الظروف التي يجب أن يحدث أبدا. وبعد والغرض من ذلك هو الانهيار في وقت مبكر في حالة حالة برنامج تالف.

يجب استخدام الاستثناءات للأخطاء التي يمكن أن يحدث ذلك، و يجب عليك دائما إنشاء فئات الاستثناءات الخاصة بك.


على سبيل المثال، إذا كنت تكتب وظيفة للقراءة من ملف التكوين إلى dict, ، يجب أن يرفع التنسيق غير السليم في الملف ConfigurationSyntaxError, ، بينما يمكنك assert أنك لست على وشك العودة None.


في مثالك، إذا x هي مجموعة قيمة عبر واجهة المستخدم أو من مصدر خارجي، استثناء هو الأفضل.

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

تتم إزالة البيانات "تأكيد" عند تحسين التجميع. وبعد لذلك، نعم، هناك كل من اختلافات الأداء والوظيفية.

ينبعث مولد التعليمات البرمجية الحالي أي رمز ببيان تأكيد عند الطلب مطلوبا في وقت الترجمة. - بيثون 2.6.4 مستندات

كما ترى assert لتنفيذ وظائف التطبيق، ثم تحسين النشر إلى الإنتاج، سوف تعاني من عيوب "ولكن IT-Works-in dev".

يرى pythonoptimize. و -OOO.

الأغراض الأربعة من assert

افترض أنك تعمل على 200000 خط كود مع أربعة زملاء أليس، برند، كارل، ودافني. يسمونين الرمز الخاص بك، يمكنك استدعاء رمزهم.

ثم assert لديها أربعة أدوار:

  1. أبلغ أليس، برند، كارل، ودافني ما تتوقعه الكود الخاص بك.
    افترض أن لديك طريقة تعالج قائمة من tuples ويمكن منطق البرنامج كسر إذا كانت هذه tuples غير ثابتة:

    def mymethod(listOfTuples):
        assert(all(type(tp)==tuple for tp in listOfTuples))
    

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

  2. أبلغ الكمبيوتر ما تتوقعه الكود الخاص بك.
    assert يفرض السلوك المناسب من المتصلين في التعليمات البرمجية الخاصة بك. إذا كانت التعليمات البرمجية يدعو رمز Alices و Bernd، فاتصل بك، ثم بدون assert, ، إذا تعطل البرنامج في كود Alics، فقد تفترض برند أنه كان خطأ أليس، ويحقق أليس وربما يفترض أنه خطأك، والتحقيق وإخبار برند أنه كان في الواقع له. فقد الكثير من العمل.
    مع تأكيد، كل من يحصل على مكالمة خطأ، فإنها ستكون سرعان ما يمكن أن نرى أنه كان خطأهم، وليس لك. أليس، برند، وكلها تستفيد. يحفظ كميات هائلة من الوقت.

  3. أبلغ القراء من التعليمات البرمجية الخاصة بك (بما في ذلك نفسك) ما حققه الكود الخاص بك في مرحلة ما.
    افترض أن لديك قائمة بالإدخالات ويمكن لكل منها نظيفة (وهو أمر جيد) أو يمكن أن تكون سموه أو تريلا أو جليل أو مذهل (والتي ليست مقبولة). إذا كان سموثا يجب أن تكون غير مسؤولة؛ إذا كان من العصر يجب أن يكون bludoed؛ إذا كان الأمر جليليا، فيجب توخيه (ومن ثم يسير بخطى كذلك)؛ إذا كان مذهلا، فيجب أن يكون واضحا مرة أخرى إلا يوم الخميس. تحصل على الفكرة: إنها أشياء معقدة. ولكن النتيجة النهائية هي (أو يجب أن تكون) أن جميع الإدخالات نظيفة. الشيء الصحيح (TM) للقيام به هو تلخيص تأثير حلقة التنظيف الخاصة بك

    assert(all(entry.isClean() for entry in mylist))
    

    هذه التصريحات توفر صداع لكل شخص يحاول فهم ما بالضبط هذا هو أن الحلقة الرائعة تحقق. والأكثر شيوعا من هؤلاء الناس من المحتمل أن تكون نفسك.

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

في رأيي، assertمن أغراض الوثائق (1 و 3) وصيانة (2 و 4) بنفس القدر من القدر.
إبلاغ الناس قد يكون أكثر قيمة من إبلاغ الكمبيوتر لأنه يمكن أن يمنع الأخطاء ذاتها assert يهدف إلى التقاط (في حالة 1) والكثير من الأخطاء اللاحقة في أي حال.

بالإضافة إلى الإجابات الأخرى، تؤكد أنفسهم إلقاء الاستثناءات، ولكن فقط assertionErrors. من وجهة نظر نفعية، لا تكون التأكيدات غير مناسبة عندما تحتاج إلى تحكم من الحبوب الدقيقة التي تصطادها.

الشيء الوحيد الذي يخطئ حقا في هذا النهج هو أنه من الصعب إجراء استثناء وصفي للغاية باستخدام بيانات التأكيد. إذا كنت تبحث عن بناء جملة Simpler، تذكرك يمكن تفعل أيضا شيئا مثل هذا:

class XLessThanZeroException(Exception):
    pass

def CheckX(x):
    if x < 0:
        raise XLessThanZeroException()

def foo(x):
    CheckX(x)
    #do stuff here

مشكلة أخرى هي أن استخدام تأكيد التحقق من الحالة العادية هو أنه يجعل من الصعب تعطيل تأكيد تصحيح الأخطاء باستخدام علامة "لو".

كما قيل سابقا، يجب استخدام التأكيدات عند عدم الوصول إلى التعليمات البرمجية الخاصة بك نقطة، مما يعني وجود خطأ هناك. ربما السبب الأكثر فائدة أستطيع أن أرى استخدام تأكيد هو ثابت / قبل / postcondition. هذه شيء يجب أن يكون صحيحا في بداية أو نهاية كل تخصيص لحلقة أو وظيفة.

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

def SumToN(n):
    if n <= 0:
        raise ValueError, "N must be greater than or equal to 0"
    else:
        return RecursiveSum(n)

def RecursiveSum(n):
    #precondition: n >= 0
    assert(n >= 0)
    if n == 0:
        return 0
    return RecursiveSum(n - 1) + n
    #postcondition: returned sum of 1 to n

غالبا ما يتم تمثيل هذه الثباتات حلقة بتأكيد.

كلمة اللغة الإنجليزية يجزم هنا يستخدم بمعنى أقسم, يؤكد, اعترف. وبعد هذا لا يعني ذلك "التحقق من" أو "يجب ان يكون". وبعد هذا يعني انه أنت كما هو المبرمج يبذل بيان اليمين الدستورية هنا:

# I solemnly swear that here I will tell the truth, the whole truth, 
# and nothing but the truth, under pains and penalties of perjury, so help me FSM
assert answer == 42

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

يكون هناك مشكلة في الأداء؟

  • يرجى تذكرنا "اجعلها تعمل أولا قبل أن تجعلها تعمل بسرعة".
    عادة ما تكون قليلة في المئة من أي برنامج ذات صلة بسرعتها. يمكنك دائما طرد أو تبسيط assert إذا أثبتت أن تكون مشكلة في الأداء - ومعظمها لن يفعلها أبدا.

  • كن pragmatic.:
    افترض أن لديك طريقة تعالج قائمة غير فارغة من TUPLES و LOGIC البرنامج ستكسر إذا كانت هذه tuples غير ثابتة. يجب ان تكتب:

    def mymethod(listOfTuples):
        assert(all(type(tp)==tuple for tp in listOfTuples))
    

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

    def mymethod(listOfTuples):
        assert(type(listOfTuples[0])==tuple)  # in fact _all_ must be tuples!
    

    وهو رخيص ولكن من المحتمل أن يصطاد معظم فعلي أخطاء البرنامج على أي حال.

هناك إطار يسمى JBoss سالول بالنسبة إلى Java التي تقوم بمراقبة وقت التشغيل لتأكيد قواعد الأعمال، والتي تجيب على الجزء الثاني من سؤالك. ومع ذلك، أنا غير متأكد إذا كان هناك إطار لهذا الإطار لبثون.

وهي تؤكد أن تسجيل الوصول
1.صالح الشرط ،
2.صالحة البيان ،
3.صحيح المنطق ؛
من التعليمات البرمجية المصدر.بدلا من فشل المشروع كله أنه يعطي إنذار بأن شيئا ما غير مناسب في الملف المصدر.

في المثال 1 ، منذ متغير 'شارع' ليس nul.لذلك لا يوجد أي تأكيد أو استثناء على المثارة.

مثال 1:

#!/usr/bin/python

str = 'hello Pyhton!'
strNull = 'string is Null'

if __debug__:
    if not str: raise AssertionError(strNull)
print str

if __debug__:
    print 'FileName '.ljust(30,'.'),(__name__)
    print 'FilePath '.ljust(30,'.'),(__file__)


------------------------------------------------------

Output:
hello Pyhton!
FileName ..................... hello
FilePath ..................... C:/Python\hello.py

في المثال 2 ، فار 'شارع' هو nul.لذلك نحن توفير المستخدم من المضي قدما من خلل البرنامج من قبل تأكيد البيان.

مثال 2:

#!/usr/bin/python

str = ''
strNull = 'NULL String'

if __debug__:
    if not str: raise AssertionError(strNull)
print str

if __debug__:
    print 'FileName '.ljust(30,'.'),(__name__)
    print 'FilePath '.ljust(30,'.'),(__file__)


------------------------------------------------------

Output:
AssertionError: NULL String

هذه اللحظة نحن لا نريد التصحيح وأدركت التأكيد على مسألة في التعليمات البرمجية المصدر.تعطيل الأمثل العلم

بيثون -O assertStatement.py
لا شيء سوف تحصل على الطباعة

في IDE مثل PTVS، Pycharm، الجناح assert isinstance() يمكن استخدام البيانات لتمكين إكمال التعليمات البرمجية لبعض الكائنات غير الواضحة.

إذا كنت تتعامل مع القانون القديم الذي يعتمد على assert للعمل بشكل صحيح، على الرغم من فإنه لا ينبغي, ، بعد ذلك إضافة التعليمة البرمجية التالية هو حل سريع حتى تجد الوقت لاستكشاف Refactor:

try:
    assert False
    raise Exception('Python Assertions are not working. This tool relies on Python Assertions to do its job. Possible causes are running with the "-O" flag or running a precompiled (".pyo" or ".pyc") module.')
except AssertionError:
    pass
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top