ننشر اليوم الجزء الثاني من ترجمة المادة ، المكرسة لكتابة التعليقات التوضيحية في بيثون.

→
الجزء الأولكيف تدعم بايثون أنواع البيانات؟
بيثون هي لغة مكتوبة بشكل حيوي. هذا يعني أنه يتم فحص أنواع المتغيرات المستخدمة فقط أثناء تنفيذ البرنامج. في المثال الوارد في الجزء السابق من المقالة ، يمكن للمرء أن يرى أن المبرمج الذي يكتب في بيثون لا يحتاج إلى تخطيط أنواع المتغيرات والتفكير في مقدار الذاكرة اللازمة لتخزين بياناته.
إليك ما يحدث عند إعداد شفرة Python الخاصة بك للتنفيذ: "في Python ، يتم تحويل التعليمات البرمجية المصدر باستخدام CPython إلى نموذج أبسط كثيرًا يسمى bytecode. يتكون رمز البايت من تعليمات تشبه في جوهرها إرشادات المعالج. لكن لا يتم تنفيذها بواسطة المعالج ، ولكن بواسطة نظام برنامج يسمى الجهاز الظاهري. (لا يتعلق الأمر بالأجهزة الافتراضية التي تتيح لك إمكاناتها تشغيل أنظمة التشغيل بأكملها فيها. وفي حالتنا ، فهذه بيئة تمثل إصدارًا مبسطًا من البيئة المتاحة للبرامج التي تعمل على المعالج). "
كيف يعرف CPython أنواع المتغيرات التي يجب أن تكون عند إعداد برنامج للتنفيذ؟ بعد كل شيء ، لم نشير إلى هذه الأنواع. CPython لا يعرف عن هذا. إنه يعلم فقط أن المتغيرات هي كائنات. كل شيء في Python هو
كائن ، على الأقل حتى يتضح أن هناك شيئًا أكثر تحديداً.
على سبيل المثال ، تعتبر Python كل سلسلة محاطة بعلامات اقتباس مفردة أو مزدوجة. إذا واجه Python رقماً ، فسيعتبر أن القيمة المقابلة لها من نوع رقمي. إذا حاولنا القيام بشيء مع كيان لا يمكن القيام به مع كيان من نوعه ، فستعلمنا بايثون لاحقًا.
خذ بعين الاعتبار رسالة الخطأ التالية التي تظهر عند محاولة إضافة سلسلة ورقم:
name = 'Vicki' seconds = 4.71; --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-9-71805d305c0b> in <module> 3 4 ----> 5 name + seconds TypeError: must be str, not float
يخبرنا النظام أنه لا يمكن إضافة سلاسل وأرقام الفاصلة العائمة. علاوة على ذلك ، فإن حقيقة أن
name
عبارة عن سلسلة ،
seconds
عبارة عن رقم ، لم تهم النظام حتى جرت محاولة لإضافة
name
seconds
.
بمعنى آخر ، يمكن وصفه على
النحو التالي : "يتم استخدام كتابة البط عند القيام بالإضافة. بيثون غير مهتم بأي نوع يحتوي عليه كائن معين. كل ما يهتم به النظام هو ما إذا كان سيعيد مكالمة ذات معنى إلى طريقة الإضافة. إذا لم يكن الأمر كذلك ، فسيصدر خطأ ".
ماذا يعني ذلك؟ هذا يعني أننا إذا كتبنا برامج في Python ، فلن نتلقى رسالة خطأ حتى يتم تشغيل مترجم CPython في تنفيذ نفس السطر الذي يوجد به خطأ.
كان هذا النهج غير مريح عند تطبيقها في فرق العمل في المشاريع الكبيرة. والحقيقة هي أنه في مثل هذه المشاريع لا يعملون مع متغيرات منفصلة ، ولكن مع هياكل البيانات المعقدة. في مثل هذه المشروعات ، يتم استدعاء بعض الوظائف من قبل الآخرين ، وتسمى هذه الوظائف بدورها ببعض الوظائف الأخرى. يجب أن يكون أعضاء الفريق قادرين على التحقق بسرعة من الرمز لمشاريعهم. إذا لم يتمكنوا من كتابة اختبارات جيدة تكتشف الأخطاء في المشاريع قبل طرحها في الإنتاج ، فهذا يعني أن مثل هذه المشاريع يمكن أن تتوقع مشاكل كبيرة.
بالمعنى الدقيق للكلمة ، هنا نأتي إلى محادثة حول التعليقات التوضيحية في Python.
يمكننا القول ، بشكل عام ، إن استخدام التعليقات التوضيحية للكتابة له
نقاط قوة كثيرة. إذا كنت تعمل مع هياكل بيانات معقدة أو وظائف تتطلب العديد من قيم الإدخال ، فإن استخدام التعليقات التوضيحية يبسط إلى حد كبير العمل مع الهياكل والوظائف المماثلة. خاصة - بعض الوقت بعد إنشائها. إذا كان لديك وظيفة واحدة فقط مع معلمة واحدة ، كما هو موضح في الأمثلة الواردة هنا ، فإن العمل مع هذه الوظيفة في غاية البساطة ، على أي حال.
ماذا لو احتجنا إلى العمل مع وظائف معقدة تأخذ العديد من قيم الإدخال التي تشبه هذه من وثائق
PyTorch :
def train(args, model, device, train_loader, optimizer, epoch): model.train() for batch_idx, (data, target) in enumerate(train_loader): data, target = data.to(device), target.to(device) optimizer.zero_grad() output = model(data) loss = F.nll_loss(output, target) loss.backward() optimizer.step() if batch_idx % args.log_interval == 0: print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format( epoch, batch_idx * len(data), len(train_loader.dataset), 100. * batch_idx / len(train_loader), loss.item()))
ما هو
model
؟ بالطبع ، يمكننا الحفر في قاعدة الكود ومعرفة:
model = Net().to(device)
ولكن سيكون من الرائع أن تتمكن فقط من تحديد نوع
model
في توقيع الوظيفة وتنقذ نفسك من تحليل الكود غير الضروري. ربما يبدو مثل هذا:
def train(args, model (type Net), device, train_loader, optimizer, epoch):
ماذا عن
device
؟ إذا بحثت عن الكود ، فيمكنك معرفة ما يلي:
device = torch.device("cuda" if use_cuda else "cpu")
الآن نحن نواجه مسألة ما
torch.device
. هذا نوع خاص من PyTorch. يمكن العثور على وصفه في
القسم المقابل من وثائق PyTorch.
سيكون من الرائع أن نتمكن من تحديد
device
الكتابة في قائمة وسيطة الوظيفة. وبالتالي ، فإننا نوفر الكثير من الوقت لأولئك الذين سيتعين عليهم تحليل هذا الرمز.
def train(args, model (type Net), device (type torch.Device), train_loader, optimizer, epoch):
هذه الاعتبارات يمكن أن تستمر لفترة طويلة جدا.
نتيجةً لذلك ، اتضح أن تعليقات التعليقات التوضيحية مفيدة جدًا لشخص يكتب رمزًا. لكنهم يستفيدون أيضًا من يقرأون كود الآخرين. من الأسهل بكثير قراءة التعليمات البرمجية المكتوبة من التعليمات البرمجية ، لفهم ما عليك التعامل مع ما هو الكيان. اكتب التعليقات التوضيحية تعمل على تحسين إمكانية قراءة التعليمات البرمجية.
إذاً ، ما الذي تم فعله في بيثون لتوصيل الكود إلى نفس مستوى قابلية القراءة الذي يميز الشفرة المكتوبة بلغات مطبوعة بشكل ثابت؟
اكتب التعليقات التوضيحية في Python
نحن الآن على استعداد للتحدث بجدية عن التعليقات التوضيحية في Python. عند قراءة البرامج المكتوبة في Python 2 ، يمكن للمرء أن يرى أن المبرمجين زودوا كودهم بتلميحات لإخبار قارئات الكود عن نوع المتغيرات أو القيم التي ترجعها الدالات.
رمز مماثل بدا في الأصل مثل
هذا :
users = []
اكتب التعليقات التوضيحية المستخدمة لتكون تعليقات بسيطة. لكن حدث أن بدأت بيثون بالتحول تدريجياً نحو طريقة أكثر تناسقًا للتعامل مع التعليقات التوضيحية. على وجه الخصوص ، نحن نتحدث عن ظهور الوثيقة
PEP 3107 ، المكرسة للتعليق على الوظائف.
بعد ذلك ، بدأ العمل في
PEP 484 . تم تطوير هذا المستند ، المخصص لكتابة التعليقات التوضيحية ، في اتصال وثيق مع mypy ، مشروع DropBox ، والذي يهدف إلى التحقق من الأنواع قبل تشغيل البرامج النصية. باستخدام mypy ، تجدر الإشارة إلى أن تدقيق النوع لا يتم تنفيذه أثناء تنفيذ البرنامج النصي. يمكن تلقي رسالة خطأ في وقت التشغيل ، على سبيل المثال ، إذا حاولت إنشاء شيء من هذا النوع لا يدعمه هذا النوع. قل - إذا حاولت
.pop()
قاموس أو استدعاء الأسلوب
.pop()
لسلسلة.
إليك ما يمكنك تعلمه من PEP 484 حول تفاصيل تنفيذ التعليقات التوضيحية: "على الرغم من أن هذه التعليقات التوضيحية متوفرة في وقت التشغيل من خلال سمة
annotations
المعتادة ، لا يتم إجراء اختبارات النوع في وقت التشغيل. بدلاً من ذلك ، ينص هذا الاقتراح على وجود أداة منفصلة منفصلة للتحقق من النوع ، والتي يمكن للمستخدم ، إذا رغب في ذلك ، التحقق من شفرة المصدر لبرامجه. بشكل عام ، تعمل أداة التحقق من النوع المشابهة كجهاز قوي للغاية. "على الرغم من أن المستخدمين الأفراد يمكنهم بالطبع استخدام أداة مشابهة لفحص الأنواع في وقت التشغيل ، إما لتنفيذ منهجية التصميم حسب العقد أو لتنفيذ تحسين JIT. لكن تجدر الإشارة إلى أن هذه الأدوات لم تصل بعد إلى مرحلة استحقاق كافية."
كيف يبدو العمل مع التعليقات التوضيحية للنوع العملي؟
على سبيل المثال ، يعني استخدامها إمكانية تسهيل العمل في IDEs المختلفة. لذلك ،
PyCharm ، العروض ، بناء على معلومات النوع ، واستكمال التعليمات البرمجية والتحقق. تتوفر ميزات مماثلة في رمز VS.
تعد التعليقات التوضيحية مفيدة لسبب آخر: فهي تحمي المطور من الأخطاء الغبية.
هنا مثال رائع على هذه الحماية.
لنفترض أننا أضفنا أسماء الأشخاص إلى القاموس:
names = {'Vicki': 'Boykis', 'Kim': 'Kardashian'} def append_name(dict, first_name, last_name): dict[first_name] = last_name append_name(names,'Kanye',9)
إذا سمحنا بذلك ، سيكون هناك العديد من الإدخالات التي تم تكوينها بشكل غير صحيح في القاموس.
دعونا إصلاح هذا:
from typing import Dict names_new: Dict[str, str] = {'Vicki': 'Boykis', 'Kim': 'Kardashian'} def append_name(dic: Dict[str, str] , first_name: str, last_name: str): dic[first_name] = last_name append_name(names_new,'Kanye',9.7) names_new
تحقق الآن من هذا الرمز باستخدام mypy واحصل على ما يلي:
(kanye) mbp-vboykis:types vboykis$ mypy kanye.py kanye.py:9: error: Argument 3 to "append_name" has incompatible type "float"; expected "str"
يمكن ملاحظة أن mypy لا يسمح باستخدام الأرقام التي يتوقع أن تكون فيها السلسلة. يُنصح أولئك الذين يرغبون في استخدام مثل هذه الاختبارات على أساس منتظم بتضمين mypy حيث يتم إجراء اختبار الكود في أنظمة تكاملهم المستمرة.
اكتب تلميحات في IDEs المختلفة
أحد أهم فوائد استخدام التعليقات التوضيحية للنوع هي أنها تسمح لمبرمجي Python باستخدام ميزات إكمال التعليمات البرمجية نفسها في مختلف IDEs المتوفرة للغات المكتوبة بشكل ثابت.
على سبيل المثال ، افترض أن لديك رمزًا يشبه ما يلي. هذا هو بضع وظائف من الأمثلة السابقة ملفوفة في الفصول الدراسية.
from typing import Dict class rainfallRate: def __init__(self, hours, inches): self.hours= hours self.inches = inches def calculateRate(self, inches:int, hours:int) -> float: return inches/hours rainfallRate.calculateRate() class addNametoDict: def __init__(self, first_name, last_name): self.first_name = first_name self.last_name = last_name self.dict = dict def append_name(dict:Dict[str, str], first_name:str, last_name:str): dict[first_name] = last_name addNametoDict.append_name()
والشيء الجميل هو أننا ، بمبادرة منا ، قمنا بإضافة وصف للنوع إلى الكود ، يمكننا ملاحظة ما يحدث في البرنامج عندما يتم استدعاء أساليب الفصل:
نصائح IDE النوعالشروع في الشروع في الكتابة
يمكنك العثور على توصيات جيدة في وثائق mypy فيما يتعلق بما يجب البدء به عند بدء كتابة التعليمات البرمجية:
- بدء صغير - تأكد من أن بعض الملفات التي تحتوي على تعليقات توضيحية متعددة يتم التحقق منها باستخدام mypy.
- كتابة السيناريو لتشغيل mypy. هذا سوف يساعد في تحقيق نتائج اختبار متسقة.
- تشغيل mypy في خطوط أنابيب CI لمنع أخطاء الكتابة.
- التعليق التدريجي على الوحدات التي يتم استخدامها في أغلب الأحيان في المشروع.
- إضافة التعليقات التوضيحية إلى التعليمات البرمجية الموجودة التي تقوم بتعديلها ؛ تزويدهم بالكود الجديد الذي تكتبه.
- استخدم MonkeyType أو PyAnnotate لتعليق التعليقات القديمة تلقائيًا.
قبل الشروع في شرح الشفرة الخاصة بك ، سيكون من المفيد لك التعامل مع شيء ما.
أولاً ، ستحتاج إلى استيراد الوحدة النمطية
للكتابة في الكود إذا كنت تستخدم شيئًا آخر غير السلاسل والأعداد الصحيحة والمنطقية وقيم أنواع بيثون الأساسية الأخرى.
ثانيا ، هذه الوحدة تجعل من الممكن العمل مع عدة أنواع معقدة. من بينها
Dict
،
Tuple
،
List
and
Set
. إنشاء النموذج
Dict[str, float]
يعني أنك تريد العمل مع قاموس تستخدم عناصره سلسلة كمفتاح ورقم الفاصلة العائمة كقيمة. هناك أيضا أنواع تسمى
Optional
Union
.
ثالثًا ، أنت بحاجة إلى التعرف على تنسيق التعليقات التوضيحية:
import typing def some_function(variable: type) -> return_type: do_something
إذا كنت تريد معرفة المزيد حول كيفية بدء تطبيق التعليقات التوضيحية على الأنواع في مشاريعك ، أود أن أشير إلى أن الكثير من البرامج التعليمية الجيدة مخصصة لهذا الغرض.
هنا واحد منهم. أنا أعتبرها الأفضل. بعد إتقانها ، سوف تتعلم عن التعليق التوضيحي للرمز والتحقق منه.
النتائج. هل يستحق استخدام التعليقات التوضيحية في بيثون؟
الآن دعنا نسأل أنفسنا إذا كان يجب عليك استخدام التعليقات التوضيحية في Python. في الواقع ، يعتمد ذلك على ميزات مشروعك. إليكم ما يقوله غيدو فان روسوم في وثائق mypy حول هذا: "الغرض من mypy ليس إقناع الجميع بكتابة كود Python المكتوب بشكل ثابت. الكتابة الثابتة اختيارية تمامًا الآن وفي المستقبل. هدف Mypy هو إعطاء المبرمجين بيثون المزيد من الخيارات. هو جعل Python بديلاً أكثر تنافسية للغات المطبوعة بشكل ثابت المستخدمة في المشاريع الكبيرة. إنها زيادة إنتاجية المبرمجين وتحسين جودة البرمجيات. "
الوقت اللازم لتكوين mypy وتخطيط الأنواع اللازمة لبرنامج معين لا يبرر نفسه في المشروعات الصغيرة وأثناء التجارب (على سبيل المثال ، تلك التي أجريت في Jupyter). ما المشروع الذي يجب اعتباره صغيرًا؟ ربما لا يتجاوز حجمه ، وفقًا لتقديرات دقيقة ، 1000 سطر.
كتابة التعليقات التوضيحية منطقية في المشروعات الكبيرة. هناك يمكنهم ، على وجه الخصوص ، توفير الكثير من الوقت. نحن نتحدث عن المشاريع التي طورتها مجموعات من المبرمجين ، عن الحزم ، عن الكود ، والتي تستخدم في تطوير أنظمة التحكم في الإصدار وخطوط أنابيب CI.
أعتقد أن التعليقات التوضيحية في العامين المقبلين ستصبح أكثر شيوعًا من الآن ، ناهيك عن حقيقة أنها قد تتحول إلى أداة يومية منتظمة. وأعتقد أن الشخص الذي يبدأ العمل معهم قبل الآخرين لن يفقد أي شيء.
أعزائي القراء! هل تستخدم التعليقات التوضيحية في مشاريع بايثون الخاصة بك؟
