سؤال

لم أكن حقا اهتماما كبيرا في تطوير Python 3 كما كنت قد أحببت، ولاحظ فقط بعض تغييرات بناء الجملة الجديدة المثيرة للاهتمام. على وجه التحديد من هذا حتى الإجابة وظيفة التعليق التعليق التوضيحي

def digits(x:'nonnegative number') -> "yields number's digits":
    # ...

عدم معرفة أي شيء عن هذا، اعتقدت أنه ربما يمكن استخدامه لتنفيذ الكتابة الثابتة في بيثون!

بعد بعض البحث، يبدو أن هناك مناقشة كبيرة فيما يتعلق بالكتابة الثابتة (اختياري تماما) في بيثون، مثل تلك المذكورة في بيب 3107., ، و "إضافة الكتابة الثابتة الاختيارية إلى Python"الجزء 2)

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

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

المحلول

شكرا لقراءة التعليمات البرمجية الخاصة بي!

في الواقع، ليس من الصعب إنشاء شرح إشراف عام في بيثون. ها هي بلدي تأخذ:

'''Very simple enforcer of type annotations.

This toy super-decorator can decorate all functions in a given module that have 
annotations so that the type of input and output is enforced; an AssertionError is
raised on mismatch.

This module also has a test function func() which should fail and logging facility 
log which defaults to print. 

Since this is a test module, I cut corners by only checking *keyword* arguments.

'''

import sys

log = print


def func(x:'int' = 0) -> 'str':
    '''An example function that fails type checking.'''
    return x


# For simplicity, I only do keyword args.
def check_type(*args):
    param, value, assert_type = args
    log('Checking {0} = {1} of {2}.'.format(*args))
    if not isinstance(value, assert_type):
        raise AssertionError(
            'Check failed - parameter {0} = {1} not {2}.'
            .format(*args))
    return value

def decorate_func(func):    
    def newf(*args, **kwargs):
        for k, v in kwargs.items():
            check_type(k, v, ann[k])
        return check_type('<return_value>', func(*args, **kwargs), ann['return'])

    ann = {k: eval(v) for k, v in func.__annotations__.items()}
    newf.__doc__ = func.__doc__
    newf.__type_checked = True
    return newf

def decorate_module(module = '__main__'):
    '''Enforces type from annotation for all functions in module.'''
    d = sys.modules[module].__dict__
    for k, f in d.items():
        if getattr(f, '__annotations__', {}) and not getattr(f, '__type_checked', False):
            log('Decorated {0!r}.'.format(f.__name__))
            d[k] = decorate_func(f)


if __name__ == '__main__':
    decorate_module()

    # This will raise AssertionError.
    func(x = 5)

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

ولكن في الحياة الحقيقية، غالبا ما تخلط كميات نفس الشيء نوع الكمبيوتر كما يراها المترجم ولكن مختلفة بوضوح نوع الإنسان, على سبيل المثال، يحتوي المقتطف التالي على خطأ واضح:

height = 1.75 # Bob's height in meters.
length = len(sys.modules) # Number of modules imported by program.
area = height * length # What's that supposed to mean???

يجب أن يرى أي إنسان على الفور خطأ في السطر أعلاه بشرط أنه يعرف "النوع البشري" للمتغيرات height و length على الرغم من أنها تتطلع إلى الكمبيوتر كما قانونية تماما الضرب int و float.

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

الآن إذا كان شخص ما هو تطبيق نوع من مكتبة Pythonic لجهة خارجية من شأنها أن تعين تلقائيا بيانات العالم الحقيقي لها نوع الإنسان ثم اعتنى بتحويل هذا النوع مثل width * height -> area وفرض ذلك الاختيار مع التعليقات التوضيحية الوظيفة، أعتقد أن هذا سيكون من الفحص من النوع يمكن أن يستخدمه الناس حقا!

نصائح أخرى

كما هو مذكور في هذا PEP، يعد التحقق من النوع الثابت أحد التطبيقات المحتملة التي يمكن استخدامها التي يمكن استخدامها التي يمكن استخدامها من خلالها، لكنهم يغادرونها إلى مكتبات الطرف الثالث لتحديد كيفية القيام بذلك. وهذا هو، لن يكون هناك تنفيذ رسمي في بيثون الأساسية.

فيما يتعلق بتنفيذات الطرف الثالث، هناك بعض القصاصات (مثل http://code.activestate.com/recipes/572161/)، الذي يبدو أن تفعل الوظيفة جيدا.

تعديل:

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

هذه ليست إجابة على السؤال مباشرة، لكنني اكتشفت شوكة بيثون تضيف كتابة ثابتة: mypy-lang.org., بالطبع لا يمكن للمرء الاعتماد عليه لأنه لا يزال مسعى صغير، ولكن مثيرا للاهتمام.

لا يمكن تنفيذ "الكتابة الساكنة" في Python إلا بحيث يتم التحقق من النوع في وقت التشغيل، مما يعني أنه يبطئ التطبيق. لذلك أنت لا تريد ذلك كعنيمة. بدلا من ذلك، تريد بعض أساليبك للتحقق من مدخلاتها. يمكن القيام بذلك بسهولة مع تأكيد عادي، أو مع ديكور إذا كنت (عن طريق الخطأ) تعتقد أنك بحاجة إليها كثيرا.

هناك أيضا بديل لفحص النوع الثابت، وهذا هو استخدام بنية مكون موجهة نحو جانب من جوانب مثل بنية مكون ZOPE. بدلا من التحقق من النوع، يمكنك تكييفها. لذلك بدلا من:

assert isinstance(theobject, myclass)

أنت تفعل هذا:

theobject = IMyClass(theobject)

إذا كان theobject ينفذ بالفعل iMyclass لا يحدث شيء. إذا لم يكن الأمر كذلك، فسيتم البحث عن محول يلتف مهما هو imyclass، واستخدامها بدلا من theobject. إذا لم يتم العثور على محول، فستحصل على خطأ.

هذا مجمع بين الدينامكية من الثعبان مع الرغبة في الحصول على نوع معين بطريقة محددة.

بالتأكيد، يبدو الكتابة الثابتة قليلا "Unpythonic" ولا أستخدمها طوال الوقت. ولكن هناك حالات (مثل فصول متداخلة، كما في تحليل اللغة المحددة للمجال) حيث يمكن أن تسريع تطورك حقا.

ثم أفضل استخدام beartype. وأوضح في هذا بريد*. يأتي مع ريبو جيت، واختبارات وشرح ما يمكن وما لا يستطيع فعله ... وأنا أحب الاسم؛)

* من فضلك لا تولي اهتماما لتشجيع سيسيل حول سبب وقوع بيثون مع البطاريات المدرجة في هذه الحالة.

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